zoukankan      html  css  js  c++  java
  • 航空路线问题(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
    ",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]<<"
    " ;
    75     for(int i=1;i<=sz1;i++) if(hh[i] > 1) cout<<p[hh[i]]<<"
    " ;
    76     for(int i=sz2;i;i--) if(gg[i] > 1) cout<<p[gg[i]]<<"
    " ; cout<<p[1]<<"
    " ;
    77     return 0 ;
    78 }

     

  • 相关阅读:
    JavaScript面试题
    HTML&&css面试题
    nodejs面试题
    linux上安装apache
    linux上安装mysql
    linux基础命令学习(三)Vim使用
    linux基础命令学习(一)
    spring学习(六)注解方式实现AOP
    spring学习(五)详细介绍AOP
    spring学习(一)spring简介
  • 原文地址:https://www.cnblogs.com/zub23333/p/8685992.html
Copyright © 2011-2022 走看看