【线性规划与网络流24题 11】航空路线
来源:互联网 发布:裤哥战哭淘宝模特视频 编辑:程序博客网 时间:2024/05/20 11:48
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
8 9VancouverYellowknifeEdmontonCalgaryWinnipegTorontoMontrealHalifaxVancouver EdmontonVancouver CalgaryCalgary WinnipegWinnipeg TorontoToronto HalifaxMontreal HalifaxEdmonton MontrealEdmonton YellowknifeEdmonton Calgary
Sample Output
7/*VancouverEdmontonMontrealHalifaxTorontoWinnipegCalgaryVancouver*/
这个题,网上有很多的题解和解释啦,我还是希望提出自己的想法。
首先,分类是:最大费用最大流
求最大费用,我使用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题 11】航空路线
- 线性规划与网络流24——航空路线问题
- 【网络流24题】航空路线问题
- [网络流24题]航空路线问题
- [网络流24题 #11]航空路线问题
- 航空路线问题[网络流24题之11]
- 网络流24题11. 航空路线问题
- 网络流24题之T11 航空路线问题
- 「网络流 24 题」航空路线问题
- 线性规划与网络流24题
- 线性规划与网络流24题
- 线性规划与网络流24题索引
- 线性规划与网络流24题
- 线性规划与网络流24题
- 网络流与线性规划24题
- 线性规划与网络流 24 题 题解
- NodeJs利用fs模块,实现批量生成文件
- 第十二章 上机练习第4题
- 最小生成树(MST)求解旅行商问题
- java递归复制所有指定规则的文件到同一目录下
- socket通信基础知识点记录
- 【线性规划与网络流24题 11】航空路线
- 人工神经网络算法-BP算法原理
- jsp自定义标签
- JfreeChart生成简单的柱形图和折线图ss
- [verilog读书笔记]3.基本概念
- BASH 学习——变量
- 正则表达式
- OrmLite 轻量级ORM框架工具
- Qt creator 编译错误:无法解析的外部符号(命令)