[网络流24题]航空路线问题
题目:洛谷P2770。
题目大意:
给定一张航空图,图中顶点代表城市,边代表 2 城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。
(1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。
(2)除起点城市外,任何城市只能访问 1 次。
对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。
解题思路:题目要求找两条不重复的路径,且距离最长。
找路径不就是跑最大流吗?
那还要距离最远?最大费用最大流即可。
首先对于某个点拆成入点和出点,然后入点与出点连接容量为1,费用为0的边。
对于每两个相连的城市,从出发的出点向到达的入点连接容量为1,费用为1的边。
由于起点和终点要经过两次,所以这两个点拆出的入点向出点连接的边容量为2。
还有一个细节,如果有1到n的边,是可以直接往返的,所以有这种边,容量也为2。
最后从起点的入点到终点的出点跑最大费用最大流。
如果流量不到2,则无解。
否则费用就是旅行路线经过的城市数量。
找路径,直接从起点开始dfs,找有流量经过的边,记录下来即可。
C++ Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #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; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步