网络流24题11. 航空路线问题
2017-03-04 17:01
399 查看
航空路线问题
Description
给定一张航空图,图中顶点代表城市,边代表 2 城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。(1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。
(2)除起点城市外,任何城市只能访问 1 次。
对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。
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!”。Sample Input
8 9Vancouver
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
7Vancouver
Edmonton
Montreal
Halifax
Toronto
Winnipeg
Calgary
Vancouver
题解
走过去再走回来,可以转化为求两条从1到N的路径。每个城市只能走一次,所以将每个城市拆成xi和yi,中间从xi向yi连接一条容量为1,费用为1的边。特别的,<x1,y1>和<xn,yn>的容量为2。
如果两个城市间有航线,那么从yi向xj(i < j)连一条容量为1,费用为0的边。
求出x1到yn的最大费用最大流,如果<x1,y1>不满流,那么无解,否则答案为cost−2。
特别的,如果1到n有航线,且<x1,y1>不满流,答案即为2,并非无解。
#include<cstdio> #include<cstring> #include<iostream> #include<map> #include<string> using namespace std; const int N = 200 + 10, M = 100000 + 10, inf = 0x3f3f3f3f; struct Edge{ int fr, to, cap, flow, cost; }edg[M]; int n, m, tot, s, t; int hd , nxt[M]; int q , inq , d , p , a ; int o, ok; string ss; map<string, int> mp; void insert(int u, int v, int w, int x){ edg[tot].fr = u, edg[tot].to = v, edg[tot].cap = w, edg[tot].cost = x; nxt[tot] = hd[u], hd[u] = tot; if(u == 1 && v == n+1) o = tot; tot++; edg[tot].fr = v, edg[tot].to = u, edg[tot].cost = -x; nxt[tot] = hd[v], hd[v] = tot; tot++; } bool spfa(int &fl, int &cst){ for(int i = s; i <= t; i++) d[i] = -inf; memset(inq, 0, sizeof(inq)); d[s] = 0; p[s] = 0; a[s] = inf; int head = 0, tail = 1; q[0] = s; inq[s] = 1; while(head != tail){ int u = q[head++]; if(head == 201) head = 0; inq[u] = 0; for(int i = hd[u]; i >= 0; i = nxt[i]){ Edge &e = edg[i]; if(e.cap > e.flow && d[e.to] < d[u] + e.cost){ d[e.to] = d[u] + e.cost; p[e.to] = i; a[e.to] = min(a[u], e.cap - e.flow); if(!inq[e.to]){ q[tail++] = e.to; if(tail == 201) tail = 0; inq[e.to] = 1; } } } } if(d[t] == -inf) return false; fl += a[t]; cst += d[t] * a[t]; int u = t; while(u != s){ edg[p[u]].flow += a[t]; edg[p[u]^1].flow -= a[t]; u = edg[p[u]].fr; } return true; } void init(){ scanf("%d%d", &n, &m); memset(hd, -1, sizeof(hd)); s = 1, t = n * 2; for(int i = 1; i <= n; i++){ cin>>ss; mp[ss] = i; if(i != 1 && i != n) insert(i, i+n, 1, 1); else insert(i, i+n, 2, 1); } for(int i = 1; i <= m; i++){ cin>>ss; int t1 = mp[ss]; cin>>ss; int t2 = mp[ss]; if(t1 > t2) swap(t1, t2); if(t1 == 1 && t2 == n) ok = 1; insert(n+t1, t2, inf, 0); } } void work(){ int flow = 0, cost = 0; while(spfa(flow, cost)); if(flow < 2) if(ok) printf("%d\n", cost); else puts("No Solution!"); else printf("%d\n", cost-2); } int main(){ freopen("prog811.in", "r", stdin); freopen("prog811.out", "w", stdout); init(); work(); return 0; }
相关文章推荐
- 网络流与线性规划24题11航空路线问题
- 航空路线问题[网络流24题之11]
- 网络流24题(11)航空路线问题(最大费用最大流)
- 网络流24题航空路线问题
- 线性规划与网络流24题 11航空路线问题
- 【网络流24题】航空路线问题
- 【网络流24题】航空路线问题(最大费用流)
- 网络流二十四题之十一 —— 航空路线问题(AIRL)
- loj6122「网络流 24 题」航空路线问题
- 【线性规划与网络流24题 11】航空路线
- loj6122「网络流 24 题」航空路线问题(最长不相交路径)
- [网络流24题]航空路线问题
- [网络流24题 #11]航空路线问题
- 【网络流24题】No.11(航空路线问题 最长不相交路径 最大费用流)
- 「网络流 24 题」航空路线问题
- 线性规划与网络流24——航空路线问题
- 航空路线问题 一般网络流
- LOJ6122 「网络流 24 题 - 18」 航空路线问题 最长不相交路径 坠大费用坠大流
- [题解] [网络流二十四题(十一)] 航空路线问题(最大费用最大流)
- [网络流24题 #11]航空路线问题