您的位置:首页 > 理论基础 > 计算机网络

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

2016-05-17 21:01 435 查看

航空路线问题

Description

给定一张航空图,图中顶点代表城市,边代表 2 城市间的直通航线。

现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。

(1) 从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东

向西飞回起点(可途经若干城市)。

(2) 除起点城市外,任何城市只能访问 1 次。

对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。

Input

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

接下来的 N 行中每一行是一个城市名,可乘飞机访问这些城市。

城市名出现的顺序是从西向东。

也就是说,设 i,j 是城市表列中城市出现的顺序,当 i>j 时,表示城市 i 在城市 j 的东边,而且不会有 2 个城市在同一条经线上。

城市名是一个长度不超过 15 的字符串,串中的字符可以是字母或阿拉伯数字。

例如,AGR34 或 BEL4。

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

Output

第 1 行是旅行路线中所访问的城市总数 M。

接下来的 M+1 行是旅行路线的城市名,每行写 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] #include <iostream>
#include <cstdio>
#include <cstring>
#include <assert.h>
#include <queue>

#define MAXV 1000010
#define MAXE 100010
#define INF 0x3f3f3f3f
#define Min(x,y) ((x)<(y)?(x):(y))

#define ss 0
#define tt 100005

using namespace std;

int n,m,ans,weight,tot;

char s[110][50];
char s1[50],s2[50];

int from[MAXV],cnt,nxt[MAXV],wei[MAXV];
int head[MAXE],dis[MAXE],data[MAXV],flow[MAXV];
int pre[MAXE];
bool in_stack[MAXE];
queue<int>q;
int come[4][500],come2[4][500];

inline int in(){
int x=0;
char c=getchar();
while(c<‘0’||c>‘9’)c=getchar();
while(c>=‘0’&&c<=‘9’){x=x*10+c-‘0’;c=getchar();}
return x;
}

void add(int x,int y,int a,int b){
from[cnt]=x;nxt[cnt]=head[x];data[cnt]=y;wei[cnt]=b;flow[cnt]=a;head[x]=cnt++;
from[cnt]=y;nxt[cnt]=head[y];data[cnt]=x;wei[cnt]=-b;flow[cnt]=0;head[y]=cnt++;
}

bool BFS(){
memset(dis,0xc0,sizeof dis);
q.push(ss);dis[ss]=0;in_stack[ss]=true;
pre[ss]=pre[tt]=-1;
while(!q.empty()){
int now=q.front();
q.pop();
in_stack[now]=false;
for(int i=head[now];i!=-1;i=nxt[i]){
if(flow[i]&&wei[i]+dis[now]>dis[data[i]]){
dis[data[i]]=wei[i]+dis[now];
pre[data[i]]=(i^1);
// if(data[i]==tt)break;
if(!in_stack[data[i]]){q.push(data[i]);in_stack[data[i]]=true;}
}
}
}
return pre[tt]>0;
}

void dfs(){
tot++;
int Low=INF,tmp;
for(int i=pre[tt];i!=-1;i=pre[data[i]])Low=Min(Low,flow[i^1]);
for(int i=pre[tt];i!=-1;i=pre[data[i]]){
flow[i^1]-=Low;
flow[i]+=Low;
come[tot][++come[tot][0]]=data[i];
}
tmp=come[tot][0]+1;
for(int i=pre[tt];i!=-1;i=pre[data[i]])come2[tot][–tmp]=data[i]-n;
weight+=Low;
ans+=(dis[tt])*Low;
}

int main(){

memset(head,-1,sizeof head);
n=in();m=in();

for(int i=1;i<=n;i++){
scanf(”%s”,s[i]);
if(i==1||i==n)add(i+n,i,2,0);
else add(i+n,i,1,0);
}
add(ss,n+n,2,0);
add(1,tt,2,0);

for(int i=1;i<=m;i++){
scanf(”%s%s”,s1,s2);
int pos1,pos2;
for(pos1=1;pos1<=n;pos1++)if(0==strcmp(s[pos1],s1))break;
for(pos2=1;pos2<=n;pos2++)if(0==strcmp(s[pos2],s2))break;
if(pos1==1&&pos2==n)add(pos2,pos1+n,2,1);
else if(pos1==n&&pos2==1)add(pos1,pos2+n,2,1);
else{
if(pos1>pos2)add(pos1,pos2+n,1,1);
else add(pos2,pos1+n,1,1);
}
}

while(BFS())dfs();
if(weight<2){
printf(”No Solution!\n”);
return 0;
}
else printf(“%d\n”,ans);

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]]);
// printf(“%d\n”,come[2][0]);
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]]);
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]]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: