• [网络流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;
    }
  • 相关阅读:
    query and join operation after sharding
    Windows Phone中的几种集合控件
    什么是SOPA SOPA的危害
    自动刷新人人网API session_key方法
    Windows Phone XNA创建简单局域网游戏
    static 修饰MySqlConnection引发的异常
    $Dsu$ $on$ $Tree$ 复习
    $Noip$前的小总结哦
    $NOIP2018$ 暴踩全场计划实施方案
    $NOIP2018$ 爆踩全场记
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/8312931.html
Copyright © 2020-2023  润新知