【线性规划与网络流24题 11】航空路线
2016-09-11 15:49
471 查看
Description
给定一张航空图,图中顶点代表城市,边代表2城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。
(1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。
(2)除起点城市外,任何城市只能访问1次。
编程任务:
对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。
由于本OJ无Special Judge , 所以只需要输出最多经过的城市数
Input
第1 行有2个正整数N 和V,N 表示城市数,N<100,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!”。
*/
一行,包含一个整数或字符串,表示最多经过的城市数,如果无解,则输出"No Solution!"(不包含引号)
Sample Input
Sample Output
这个题,网上有很多的题解和解释啦,我还是希望提出自己的想法。
首先,分类是:最大费用最大流
求最大费用,我使用kuangbin模板,把所有的费用值取成负数,然后调用最小费用最大流的模板,求得结果之后对cost值取相反数
这个题运用的建模思想是:最长不相交路径
因为要求的是从1到n的两条不相交的路径
相当于最大流已经求出来了(必须是2,如果不是2,那么无解)
那么,我们在添加边的时候,需要拆点,把每个点拆成(ia)(ib)
除了1和n的任意点,添加边(ia,ib,1,-1)代表容量为1,单位费用为1
1和n添加边(ia,ib,2,-1)代表容量为2,单位费用为1
然后,可以直接到的边:(边输入边处理)
从小值的点添加边到大值的点:添加边(i+n,j,1,0)
但是如果i=1,j=n,那么需要添加的是(i+n,j,2,0)
代表是拆边之后的转移了
每条航线都是自西向东,本题可以转化为求航线图中从1到N两条不相交的路径,
使得路径长度之和最大。转化为网络流模型,就是找两条最长的增广路。
由于每个城市只能访问一次,要把城市拆成两个点,之间连接一条容量为1的边,费用设为1。
因为要找两条路径,所以起始点和终点内部的边容量要设为2。
那么费用流值-2就是两条路径长度之和,为什么减2,因为有两条容量为2的边多算了1的费用。
求最大费用最大流后,如果(<1.a>,<1.b>)不是满流,
那么我们找到的路径不够2条(可能是1条,也可能0条),所以无解
如何求转移的路径?!
这个问题想了很久,发现可以延续前几个题的思路,用深搜
因为这个题的生成路径必然是个环,我们可以从1点开始用深搜,如果遇到的点是拆点之前的ia,那么需要输出,继续搜索;如果遇到的ib,那么不能输出,继续搜索
这样搜索一圈,一定是从起点走到了终点,然后到了起点的前一个点(因为起点已经访问过了,所以必然会退出搜索)
然后在搜索外面再次输出一次起点就好
题意很好理解:但是想要转换模型是很难的:求最长两条不相交路径,用最大费用最大流解决
因为:题目中说了:流量一定是2
那么,我们的费用越大,说明走过的路径越长
把第i个城市拆分成两个顶点<i.a>,<i.b>。
1、对于每个城市i,连接(<i.a>,<i.b>)一条容量为1,费用为1的有向边,特殊地(<1.a>,<1.b>)和(<N.a>,<N.b>)容量设为2。
2、如果城市i,j(j>i)之间有航线,从<i.b>到<j.a>连接一条容量为1,费用为0的有向边。
求源<1.a>到汇<N.b>的最大费用最大流。如果(<1.a>,<1.b>)不是满流,那么无解。否则存在解,即为最大费用最大流量 - 2
对于,如何找最优的路径输出其实是很简单的
写一个dfs就好了啊
因为每个点的流量最大为2,也就是说最多一进一出
那么从起点开始往下搜索就好,如果碰到的节点编号<=n,那么就输出(拆点前的X集合的点)
否则不输出,继续搜索,这样dfs到最后一个点之后,肯定是回到起点了的
代码如下:
给定一张航空图,图中顶点代表城市,边代表2城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。
(1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。
(2)除起点城市外,任何城市只能访问1次。
编程任务:
对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。
由于本OJ无Special Judge , 所以只需要输出最多经过的城市数
Input
第1 行有2个正整数N 和V,N 表示城市数,N<100,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!”。
*/
一行,包含一个整数或字符串,表示最多经过的城市数,如果无解,则输出"No Solution!"(不包含引号)
Sample Input
8 9 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 */
这个题,网上有很多的题解和解释啦,我还是希望提出自己的想法。
首先,分类是:最大费用最大流
求最大费用,我使用kuangbin模板,把所有的费用值取成负数,然后调用最小费用最大流的模板,求得结果之后对cost值取相反数
这个题运用的建模思想是:最长不相交路径
因为要求的是从1到n的两条不相交的路径
相当于最大流已经求出来了(必须是2,如果不是2,那么无解)
那么,我们在添加边的时候,需要拆点,把每个点拆成(ia)(ib)
除了1和n的任意点,添加边(ia,ib,1,-1)代表容量为1,单位费用为1
1和n添加边(ia,ib,2,-1)代表容量为2,单位费用为1
然后,可以直接到的边:(边输入边处理)
从小值的点添加边到大值的点:添加边(i+n,j,1,0)
但是如果i=1,j=n,那么需要添加的是(i+n,j,2,0)
代表是拆边之后的转移了
每条航线都是自西向东,本题可以转化为求航线图中从1到N两条不相交的路径,
使得路径长度之和最大。转化为网络流模型,就是找两条最长的增广路。
由于每个城市只能访问一次,要把城市拆成两个点,之间连接一条容量为1的边,费用设为1。
因为要找两条路径,所以起始点和终点内部的边容量要设为2。
那么费用流值-2就是两条路径长度之和,为什么减2,因为有两条容量为2的边多算了1的费用。
求最大费用最大流后,如果(<1.a>,<1.b>)不是满流,
那么我们找到的路径不够2条(可能是1条,也可能0条),所以无解
如何求转移的路径?!
这个问题想了很久,发现可以延续前几个题的思路,用深搜
因为这个题的生成路径必然是个环,我们可以从1点开始用深搜,如果遇到的点是拆点之前的ia,那么需要输出,继续搜索;如果遇到的ib,那么不能输出,继续搜索
这样搜索一圈,一定是从起点走到了终点,然后到了起点的前一个点(因为起点已经访问过了,所以必然会退出搜索)
然后在搜索外面再次输出一次起点就好
题意很好理解:但是想要转换模型是很难的:求最长两条不相交路径,用最大费用最大流解决
因为:题目中说了:流量一定是2
那么,我们的费用越大,说明走过的路径越长
把第i个城市拆分成两个顶点<i.a>,<i.b>。
1、对于每个城市i,连接(<i.a>,<i.b>)一条容量为1,费用为1的有向边,特殊地(<1.a>,<1.b>)和(<N.a>,<N.b>)容量设为2。
2、如果城市i,j(j>i)之间有航线,从<i.b>到<j.a>连接一条容量为1,费用为0的有向边。
求源<1.a>到汇<N.b>的最大费用最大流。如果(<1.a>,<1.b>)不是满流,那么无解。否则存在解,即为最大费用最大流量 - 2
对于,如何找最优的路径输出其实是很简单的
写一个dfs就好了啊
因为每个点的流量最大为2,也就是说最多一进一出
那么从起点开始往下搜索就好,如果碰到的节点编号<=n,那么就输出(拆点前的X集合的点)
否则不输出,继续搜索,这样dfs到最后一个点之后,肯定是回到起点了的
代码如下:
#include<bits/stdc++.h> using namespace std; const int maxn=10000; const int maxm=300000; const int inf=0x3f3f3f3f; struct Edge{ int to,nxt,cap,flow,cost; }edge[maxm]; char str[maxn][50],st[50]; int Head[maxn],tol; int pre[maxn]; int dis[maxn]; int n,m,s,t,tot; bool vis[maxn]; void init(){ tol=0; memset(Head,-1,sizeof(Head)); } void addedge(int u,int v,int cap,int cost){ edge[tol].to=v; edge[tol].cap=cap; edge[tol].cost=cost; edge[tol].flow=0; edge[tol].nxt=Head[u]; Head[u]=tol++; edge[tol].to=u; edge[tol].cap=0; edge[tol].cost=-cost; edge[tol].flow=0; edge[tol].nxt=Head[v]; Head[v]=tol++; } bool spfa(int s,int t){ queue<int> q; for(int i=0;i<=tot+1;i++){ dis[i]=inf; vis[i]=false; pre[i]=-1; } dis[s]=0; vis[s]=true; q.push(s); while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=false; for(int i=Head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if (edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost){ dis[v]=dis[u]+edge[i].cost; pre[v]=i; if (!vis[v]){ vis[v]=true; q.push(v); } } } } if (pre[t]==-1) return false; return true; } int minCostMaxflow(int s,int t,int &cost){ int flow=0; cost=0; while(spfa(s,t)){ int Min=inf; for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]) if (Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow; for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){ edge[i].flow+=Min; edge[i^1].flow-=Min; cost+=edge[i].cost*Min; } flow+=Min; } return flow; } void dfs(int u){ if (u<=n&&!vis[u]) cout<<str[u]<<endl; vis[u]=true; for(int i=Head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if (edge[i].flow&&!vis[v]) dfs(v); } return; } int main(){ //freopen("input.txt","r",stdin); while(scanf("%d%d",&n,&m)!=EOF){ init(); for(int i=1;i<=n;i++) scanf("%s",str[i]); for(int i=2;i<n;i++) addedge(i,i+n,1,-1); addedge(1,1+n,2,-1); addedge(n,n+n,2,-1); s=1; t=n+n; tot=n+n; for(int i=1;i<=m;i++){ int pos1,pos2; scanf("%s",st); for(int j=1;j<=n;j++) if (strcmp(str[j],st)==0){ pos1=j; break; } scanf("%s",st); for(int j=1;j<=n;j++) if (strcmp(str[j],st)==0){ pos2=j; break; } if (pos1>pos2) swap(pos1,pos2); addedge(pos1+n,pos2,1,0); if (pos1==1&&pos2==n) addedge(n+1,n,2,0); } int Cost,Maxflow; Maxflow=minCostMaxflow(s,t,Cost); if (Maxflow<2){ //printf("Maxflow: %d\n",Maxflow); puts("No Solution!"); } else{ printf("%d\n",-Cost-2); memset(vis,false,sizeof(vis)); dfs(1); cout<<str[1]<<endl; } } return 0; }
相关文章推荐
- 线性规划与网络流24题 11航空路线问题
- 网络流与线性规划24题11航空路线问题
- 线性规划与网络流24——航空路线问题
- [线性规划与网络流24题]网络流常见模型[转载]
- 线性规划与网络流24题 17运输问题
- 线性规划与网络流24题 餐巾计划问题
- 【线性规划与网络流24题】孤岛营救问题 分层图
- 线性规划与网络流24题 17运输问题
- 线性规划与网络流24题 07试题库问题
- 【网络流24题】航空路线问题(最大费用流)
- 线性规划与网络流24题 飞行员配对方案问题
- 【线性规划与网络流 24题】已完成(3道题因为某些奇怪的原因被抛弃了QAQ)
- 【线性规划与网络流24题 1】飞行员配对方案
- 【线性规划与网络流24题 24】骑士共存问题
- 航空路线问题[网络流24题之11]
- 网络流24题11. 航空路线问题
- 线性规划与网络流24题 3.最小路径覆盖问题(nefu 481)
- [网络流24题]航空路线问题
- 线性规划与网络流24题 02太空飞行计划问题
- 【线性规划与网络流24题 10】餐巾计划