1. 程式人生 > >航空路線問題(dp解法)

航空路線問題(dp解法)

fin i++ 則無 gpo long long AI tps 同學 problem

題目鏈接: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解法)