[网络流24题]航空路线问题
Description
给定一张航空图,图中顶点代表城市,边代表$2$城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。
- 从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。
- 除起点城市外,任何城市只能访问$1$次。
求一条满足要求的最佳航空旅行路线。
Input
第$1$行有$2$个正整数$N,V$,$N$表示城市数,$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
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
HINT
$N<100$
Solution
为了限制经过次数,将每个点$i$拆成$x_i,y_i$.
从$x_i$向$y_i$连一条容量为$1$,费用为$1$的有向边($1<i<N$),
从$x_1$向$y_1$连一条容量为$2$,费用为$1$的有向边,
从$x_N$向$y_N$连一条容量为$2$,费用为$1$的有向边,
如果存在边($i,j$)($i<j$)从$y_i$向$x_j$连一条容量为$1$,费用为$0$的有向边.
求$x_1$到$y_N$的最大费用最大流.若($x_1,y_1$)满流,则有解,答案为最大费用最大流$-2$;否则,无解.
#include<cmath> #include<ctime> #include<queue> #include<stack> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define L 20 #define N 55 using namespace std; struct graph{ int nxt,to,f,w; }e[N*N<<1]; struct edge{ int e,v; }pre[N*N<<1]; int g[N<<1],dis[N<<1],nxt[N<<1],n,m,s,t,cnt=1,ans; bool v[N],inq[N<<1];char c[N][L],l[L]; queue<int> q; inline void addedge(int x,int y,int f,int w){ e[++cnt].nxt=g[x];g[x]=cnt; e[cnt].to=y;e[cnt].f=f;e[cnt].w=w; } inline void adde(int x,int y,int f,int w){ addedge(x,y,f,w);addedge(y,x,0,-w); } inline bool spfa(int u){ memset(dis,0,sizeof(dis)); memset(inq,0,sizeof(inq)); q.push(u);inq[u]=true; while(!q.empty()){ u=q.front();q.pop();inq[u]=false; for(int i=g[u];i;i=e[i].nxt){ if(e[i].f>0&&dis[u]+e[i].w>dis[e[i].to]){ dis[e[i].to]=dis[u]+e[i].w; pre[e[i].to].e=i;pre[e[i].to].v=u; if(!inq[e[i].to]){ inq[e[i].to]=true;q.push(e[i].to); } } } } return dis[t]; } inline int mf(int f){ int ret=0,d; while(f){ if(!spfa(s)) return -1; d=f; for(int i=t;i!=s;i=pre[i].v) d=min(e[pre[i].e].f,d); ret+=d*dis[t];f-=d; for(int i=t;i!=s;i=pre[i].v){ e[pre[i].e].f-=d;e[pre[i].e^1].f+=d; } } return ret; } inline void Aireen(){ scanf("%d%d",&n,&m); s=1;t=n<<1; for(int i=1;i<=n;++i) scanf("%s",c[i]); for(int i=1,j,k,tmp;i<=m;++i){ scanf("%s",l); for(j=1;strcmp(l,c[j]);++j); scanf("%s",l); for(k=1;strcmp(l,c[k]);++k); if(j>k){ tmp=j;j=k;k=tmp; } if(j==1&&k==n) adde(j+n,k,2,0); else adde(j+n,k,1,0); } adde(1,1+n,2,1); adde(n,n<<1,2,1); for(int i=2;i<n;++i) adde(i,i+n,1,1); ans=mf(2); if(ans<0){ puts("No Solution!"); return; } printf("%d\n",ans-2); printf("%s\n",c[1]); for(int i=g[s+n],j,k;i;i=e[i].nxt) if(!e[i].f&&!(i&1)){ k=e[i].to; while(k){ printf("%s\n",c[k]); v[k]=true; for(j=g[k+n],k=0;j;j=e[j].nxt) if(!e[j].f&&!(j&1)){ k=e[j].to;break; } } break; } for(int i=g[t-n],j,k;i;i=e[i].nxt) if(!e[i^1].f&&(i&1)&&!v[e[i].to-n]){ k=e[i].to-n; while(k){ printf("%s\n",c[k]);v[k]=true; for(j=g[k],k=0;j;j=e[j].nxt) if(!e[j^1].f&&(j&1)){ k=e[j].to-n;break; } } break; } } int main(){ freopen("airl.in","r",stdin); freopen("airl.out","w",stdout); Aireen(); fclose(stdin); fclose(stdout); return 0; }