网络流二十四题之十一 —— 航空路线问题(AIRL)

来源:互联网 发布:网络新媒体专业课程 编辑:程序博客网 时间:2024/05/21 21:33

航空路线问题


Description

给定一张航空图,图中顶点代表城市,边代表 2 城市间的直通航线。
现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。
(1) 从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东
向西飞回起点(可途经若干城市)。
(2) 除起点城市外,任何城市只能访问 1 次。
对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。


Input

1 行有 2 个正整数 NVN 表示城市数,N<100V 表示直飞航线数。

接下来的 N 行中每一行是一个城市名,可乘飞机访问这些城市。
城市名出现的顺序是从西向东。
也就是说,设 i,j 是城市表列中城市出现的顺序,当 i>j 时,表示城市 i 在城市 j 的东边,而且不会有 2 个城市在同一条经线上。
城市名是一个长度不超过 15 的字符串,串中的字符可以是字母或阿拉伯数字。
例如,AGR34BEL4

再接下来的 V 行中,每行有 2 个城市名,中间用空格隔开,如 city1 city2 表示 city1city2 有一条直通航线,从 city2city1 也有一条直通航线。


Output

1 行是旅行路线中所访问的城市总数 M
接下来的 M1 行是旅行路线的城市名,每行写 1 个城市名。
首先是出发城市名,然后按访问顺序列出其它城市名。
注意,最后 1 行(终点城市)的城市名必然是出发城市名。
如果问题无解,则输出“No Solution!”。


Sample Input

8 9
Vancouver
Yellowknife
Edmonton
Calgary
Winnipeg
Toronto
Montreal
Halifax
Vancouver Edmonton
Vancouver Calgary
Calgary Winnipeg
Winnipeg Toronto
Toronto Halifax
Montreal Halifax
Edmonton Montreal
Edmonton Yellowknife
Edmonton Calgary


Sample Output

7
Vancouver
Edmonton
Montreal
Halifax
Toronto
Winnipeg
Calgary
Vancouver


Solution

这是一道简单的费用流的题目。
一开始做这道题,我竟然没有发现必须要从西到东!
弄得我最开始求费用流时费了很大功夫。

步入正题。
首先,一去 —— 一回,我们完全可以看成最东方的那座城市有两条路径到最西方的城市!
将每个城市拆点,保证每个城市只经过一次。

然后将最西方的城市连上汇点,将最东方的城市连上源点。
将每一条航线的容量设为 1,费用也设为 1

然后求最大费用最大流即可。

注意:如果最西方的城市与最东方的城市直接连上了,那么这条边的容量应该为 2(因为这条边可以看作一去一回的两条路径)。


Code

[cpp]
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. #include <assert.h>  
  5. #include <queue>  
  6.   
  7. #define MAXV 1000010  
  8. #define MAXE 100010  
  9. #define INF 0x3f3f3f3f  
  10. #define Min(x,y) ((x)<(y)?(x):(y))  
  11.   
  12. #define ss 0  
  13. #define tt 100005  
  14.   
  15. using namespace std;  
  16.   
  17. int n,m,ans,weight,tot;  
  18.   
  19. char s[110][50];   
  20. char s1[50],s2[50];  
  21.   
  22. int from[MAXV],cnt,nxt[MAXV],wei[MAXV];  
  23. int head[MAXE],dis[MAXE],data[MAXV],flow[MAXV];  
  24. int pre[MAXE];  
  25. bool in_stack[MAXE];  
  26. queue<int>q;  
  27. int come[4][500],come2[4][500];   
  28.   
  29. inline int in(){  
  30.     int x=0;  
  31.     char c=getchar();  
  32.     while(c<‘0’||c>‘9’)c=getchar();  
  33.     while(c>=‘0’&&c<=‘9’){x=x*10+c-‘0’;c=getchar();}  
  34.     return x;   
  35. }  
  36.   
  37. void add(int x,int y,int a,int b){    
  38.     from[cnt]=x;nxt[cnt]=head[x];data[cnt]=y;wei[cnt]=b;flow[cnt]=a;head[x]=cnt++;    
  39.     from[cnt]=y;nxt[cnt]=head[y];data[cnt]=x;wei[cnt]=-b;flow[cnt]=0;head[y]=cnt++;     
  40. }    
  41.   
  42. bool BFS(){  
  43.     memset(dis,0xc0,sizeof dis);    
  44.     q.push(ss);dis[ss]=0;in_stack[ss]=true;    
  45.     pre[ss]=pre[tt]=-1;  
  46.     while(!q.empty()){  
  47.         int now=q.front();    
  48.         q.pop();    
  49.         in_stack[now]=false;    
  50.         for(int i=head[now];i!=-1;i=nxt[i]){    
  51.             if(flow[i]&&wei[i]+dis[now]>dis[data[i]]){  
  52.                 dis[data[i]]=wei[i]+dis[now];    
  53.                 pre[data[i]]=(i^1);    
  54. //              if(data[i]==tt)break;  
  55.                 if(!in_stack[data[i]]){q.push(data[i]);in_stack[data[i]]=true;}    
  56.             }    
  57.         }    
  58.     }    
  59.     return pre[tt]>0;    
  60. }    
  61.     
  62. void dfs(){    
  63.     tot++;  
  64.     int Low=INF,tmp;    
  65.     for(int i=pre[tt];i!=-1;i=pre[data[i]])Low=Min(Low,flow[i^1]);    
  66.     for(int i=pre[tt];i!=-1;i=pre[data[i]]){    
  67.         flow[i^1]-=Low;    
  68.         flow[i]+=Low;    
  69.         come[tot][++come[tot][0]]=data[i];  
  70.     }  
  71.     tmp=come[tot][0]+1;  
  72.     for(int i=pre[tt];i!=-1;i=pre[data[i]])come2[tot][–tmp]=data[i]-n;    
  73.     weight+=Low;  
  74.     ans+=(dis[tt])*Low;  
  75. }  
  76.   
  77. int main(){  
  78.       
  79.     memset(head,-1,sizeof head);  
  80.     n=in();m=in();  
  81.           
  82.     for(int i=1;i<=n;i++){  
  83.         scanf(”%s”,s[i]);  
  84.         if(i==1||i==n)add(i+n,i,2,0);  
  85.         else add(i+n,i,1,0);  
  86.     }  
  87.     add(ss,n+n,2,0);  
  88.     add(1,tt,2,0);  
  89.       
  90.     for(int i=1;i<=m;i++){  
  91.         scanf(”%s%s”,s1,s2);  
  92.         int pos1,pos2;  
  93.         for(pos1=1;pos1<=n;pos1++)if(0==strcmp(s[pos1],s1))break;  
  94.         for(pos2=1;pos2<=n;pos2++)if(0==strcmp(s[pos2],s2))break;  
  95.         if(pos1==1&&pos2==n)add(pos2,pos1+n,2,1);  
  96.         else if(pos1==n&&pos2==1)add(pos1,pos2+n,2,1);  
  97.         else{  
  98.             if(pos1>pos2)add(pos1,pos2+n,1,1);  
  99.             else add(pos2,pos1+n,1,1);    
  100.         }  
  101.     }  
  102.       
  103.     while(BFS())dfs();  
  104.     if(weight<2){  
  105.         printf(”No Solution!\n”);  
  106.         return 0;  
  107.     }  
  108.     else printf(“%d\n”,ans);  
  109.       
  110.     for(int i=1;i<=come[1][0];i++)if(come[1][i]!=ss&&come[1][i]!=tt&&come[1][i]>=1&&come[1][i]<=n)printf(“%s\n”,s[come[1][i]]);  
  111. //  printf(“%d\n”,come[2][0]);  
  112.     for(int i=3;i<=come[2][0];i++)if(come2[2][i]!=ss&&come2[2][i]!=tt&&come2[2][i]>=1&&come2[2][i]<=n)printf(“%s\n”,s[come2[2][i]]);  
  113.     if(tot==1)for(int i=3;i<=come[1][0];i++)if(come2[1][i]!=ss&&come2[1][i]!=tt&&come2[1][i]>=1&&come2[1][i]<=n)printf(“%s\n”,s[come2[1][i]]);  
  114.     return 0;  
  115. }  
2 0