题目:洛谷P2770。
题目大意:
给定一张航空图,图中顶点代表城市,边代表 2 城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。
(1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。
(2)除起点城市外,任何城市只能访问 1 次。
对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。
解题思路:题目要求找两条不重复的路径,且距离最长。
找路径不就是跑最大流吗?
那还要距离最远?最大费用最大流即可。
首先对于某个点拆成入点和出点,然后入点与出点连接容量为1,费用为0的边。
对于每两个相连的城市,从出发的出点向到达的入点连接容量为1,费用为1的边。
由于起点和终点要经过两次,所以这两个点拆出的入点向出点连接的边容量为2。
还有一个细节,如果有1到n的边,是可以直接往返的,所以有这种边,容量也为2。
最后从起点的入点到终点的出点跑最大费用最大流。
如果流量不到2,则无解。
否则费用就是旅行路线经过的城市数量。
找路径,直接从起点开始dfs,找有流量经过的边,记录下来即可。
C++ Code:
#include<iostream> #include<map> #include<string> #include<string.h> #include<queue> #include<vector> #include<cstdio> using namespace std; map<string,int>p; vector<int>v; queue<int>q; int n,m,cnt=-1,head[606],d[606],a[606],pre_e[606]; bool vis[606]; string s[105]; struct edge{ int from,to,cap,dis,nxt,flow; }e[605<<3]; inline void addedge(int from,int to,int cap,int dist){ e[++cnt]=(edge){from,to,cap,dist,head[from],cap}; head[from]=cnt; e[++cnt]=(edge){to,from,0,-dist,head[to],0}; head[to]=cnt; } bool spfa(int s,int t,int& flow,int& cost){ memset(a,0x3f,sizeof a); memset(pre_e,-1,sizeof a); memset(vis,0,sizeof vis); for(int i=0;i<=605;++i)d[i]=-2000000; d[s]=0; vis[s]=1; q.push(s); while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=e[i].nxt) if(e[i].cap&&d[e[i].to]<d[u]+e[i].dis){ d[e[i].to]=d[u]+e[i].dis; pre_e[e[i].to]=i; a[e[i].to]=(a[u]>e[i].cap)?e[i].cap:a[u]; if(!vis[e[i].to]){ vis[e[i].to]=1; q.push(e[i].to); } } } if(d[t]<=-2000000)return 0; flow+=a[t]; cost+=d[t]*a[t]; for(int i=t;i!=s;i=e[pre_e[i]].from){ e[pre_e[i]].cap-=a[t]; e[pre_e[i]^1].cap+=a[t]; } return 1; } int maxflow(int s,int t,int& cost){ int flow=0; cost=0; while(spfa(s,t,flow,cost)); return flow; } void find(int now){ if(now<=n)v.push_back(now); for(int i=head[now];i!=-1;i=e[i].nxt) if(e[i].cap<e[i].flow&&e[i].flow){ find(e[i].to); ++e[i].cap; break; } } int main(){ ios::sync_with_stdio(0); cin>>n>>m; memset(head,-1,sizeof head); for(int i=1;i<=n;++i){ cin>>s[i]; p[s[i]]=i; } for(int i=2;i<n;++i)addedge(i,i+n,1,0); addedge(1,n+1,2,0);addedge(n,n<<1,2,0); for(;m--;){ string u,v; cin>>u>>v; int a=p[u],b=p[v]; if(a>b)a^=b^=a^=b; if(a==1&&b==n)addedge(n+1,n,2,1);else addedge(a+n,b,1,1); } int cost; if(maxflow(1,n<<1,cost)!=2)return!printf("No Solution!"); cout<<cost<<endl; find(1); for(int i=0,sz=v.size();i<sz;++i)cout<<s[v[i]]<<endl; v.clear(); find(1); for(int i=v.size()-2;i>=0;--i)cout<<s[v[i]]<<endl; return 0; }