航空路线问题(dp解法)

Posted zubizakeli

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了航空路线问题(dp解法)相关的知识,希望对你有一定的参考价值。

  题目链接:https://www.luogu.org/problemnew/show/P2770

 

 题意:

  从左到右给你n个点,有m条边连接这些点,问从最左边的点到达最右边的点再回到最左边的点最多可以经过几个点(除了起点外每个点最多只能被经过一次)。

  

 题解:

  首先,我们可以把题意转化成从最左边的点走两条不相交的路线到达最右边的点,且使经过的点最多。标程是最大费用最大流。

  为了限流,我们把每个点i拆成两个点xi,yi,x1->y1、xn->yn连一条容量为2,费用为1的边,其他点xi->yi连一条容量为1,费用为1的边。若有i->j可达(i<j),则连yi->xj最后求x1->yn的最大费用最大流即可。若最大流等于2,则有解,为最大费用-2(因为起点和终点重复计算了);否则无解。

 

  然而,其实这题还有另一种解法!!!

  我们设dpi,j表示两条路线分别走到了i点和j点。且只往>max(i,j)的点转移。

  有同学可能会问:那如果i<j-1,而且(i+1,j)这个状态要由(i,j)转移过来怎么办呢?

  其实完全不用担心这个问题,因为(i+1,j)这个状态可以由(i+1,j-x)的状态转移过来。

  我们可以这么想,假设我们已经知道了最终答案要经过哪些点,甲和乙现在同时站在起点,对于下一个要经过的点,若在甲的路线上,就让甲走到该点,在乙的路线上就让乙走到该点。所以只往最右边的点的右边走也是可以走出最优解的。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<map>
 6 #define LL long long
 7 #define RI register int
 8 using namespace std;
 9 const int INF = 0x7ffffff ;
10 const int N = 100 + 10 ;
11 
12 inline int read() {
13     int k = 0 , f = 1 ; char c = getchar() ;
14     for( ; !isdigit(c) ; c = getchar())
15       if(c == -) f = -1 ;
16     for( ; isdigit(c) ; c = getchar())
17       k = k*10 + c-0 ;
18     return k*f ;
19 }
20 int n, m ; bool road[N][N] ; int dp[N][N], pre[N][N], typ[N][N], hh[N], gg[N] ; 
21 map<int,string>p ;
22 map<string,int>pp ;
23 
24 int dfs(int x,int y) {
25     if(dp[x][y]) return dp[x][y] ;
26     if(x+y == 1) return 0 ; 
27     int mm = min(x,y) ;
28     for(int i=0;i<mm;i++) {
29         if(road[i][x]) {
30             dp[y][x] = dp[x][y] = max(dp[x][y],dfs(i,y)+1) ;
31         }        
32         if(road[i][y]) {
33             dp[y][x] = dp[x][y] = max(dp[x][y],dfs(i,x)+1) ;
34         }    
35     }
36     if(!dp[x][y]) return -INF ;
37     return dp[x][y] ;
38 }
39 int tot = 0 ;
40 void dfss(int x,int y) {
41     hh[++tot] = x, gg[tot] = y ;
42     if(x+y == 1) return ;
43     int mm = min(x,y) ;
44     for(int i=0;i<mm;i++) {
45         if(dp[i][y] == dp[x][y]-1 && road[i][x]) {
46             dfss(i,y) ; return ;
47         }
48         if(dp[x][i] == dp[x][y]-1 && road[i][y]) {
49             dfss(x,i) ; return ;
50         }
51     }
52 }
53 
54 
55 int main() {
56     n = read(), m = read() ; string s ;
57     for(int i=1;i<=n;i++) {
58         cin>>s ; p[i] = s ; pp[s] = i ;
59     }
60     for(int i=1;i<=m;i++) {
61         string s1, s2 ; cin>>s1>>s2 ;
62         int x = pp[s1], y = pp[s2] ;
63         road[x][y] = road[y][x] = 1 ;
64         if(x == 1) road[0][y] = road[y][0] = 1 ;
65         else if(y == 1) road[0][x] = road[x][0] = 1 ;
66     }
67     dfs(n,n) ;
68     if(!dp[n][n]) { printf("No Solution!") ; return 0 ; }
69     printf("%d\n",dp[n][n]) ;
70     for(int i=1;i<n;i++) if(dp[i][n] == dp[n][n]-1) { dfss(i,n) ; break ; }
71     sort(hh+1,hh+tot+1) ; sort(gg+1,gg+tot+1) ;
72     int sz1 = unique(hh+1,hh+tot+1) - (hh+1) ;
73     int sz2 = unique(gg+1,gg+tot+1) - (gg+1) ;
74     cout<<p[1]<<"\n" ;
75     for(int i=1;i<=sz1;i++) if(hh[i] > 1) cout<<p[hh[i]]<<"\n" ;
76     for(int i=sz2;i;i--) if(gg[i] > 1) cout<<p[gg[i]]<<"\n" ; cout<<p[1]<<"\n" ;
77     return 0 ;
78 }

 

 

以上是关于航空路线问题(dp解法)的主要内容,如果未能解决你的问题,请参考以下文章

P2770 航空路线问题

网络流24题 洛谷 2770 航空路线问题

网络流24题No.11(航空路线问题 最长不相交路径 最大费用流)

[网络流24题] 航空路线问题

滑雪(dp或记忆化搜索)

[luoguP2770] 航空路线问题(最小费用最大流)