[网络流24题]航空路线问题

题目:洛谷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;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/8312931.html