计蒜客 Our Journey of Dalian Ends 拆点+最小费用最大流
2017-09-21 10:54
513 查看
题目
Our Journey of Dalian Ends题解
需要用到最小费用最大流的知识,不会的话可以先学习一下。有了这个前置知识,这道题就很简单了。
首先由于每个城市只能经过一次,所以要先进行拆点。将一个城市拆成两个点,这两个点单向流动,容量为1,路径长度为0。
点拆好后,要再加两个点,三条路径。一个超级源点,连接上海,流量为2,路径长度为1;一个超级汇点,分别连大连和上海,流量为1,路径长度为0。
最后跑一个从超级源点到超级汇点的最小费用最大流就好了。如果答案流量为2,就把费用输入,但如果流量小于2,就输出-1。
代码
#include <algorithm> #include <bitset> #include <cstring> #include <cstdio> #include <cmath> #include <cstdlib> #include <climits> #include <iostream> #include <list> #include <map> #include <queue> #include <set> #include <stack> #include <string> #include <vector> using namespace std; const int MAX = 50000; struct Edge { int from,to; long long cap,flow,cost; Edge(int u,int v,long long ca,long long f,long long co):from(u),to(v),cap(ca),flow(f),cost(co){}; }; struct MCMF { int n; vector<Edge> edges; vector<int> G[MAX]; int inq[MAX];//是否在队列中 long long d[MAX];//距离 int p[MAX];//上一条弧 long long a[MAX];//可改进量 void init(int n)//初始化 { this->n=n; for(long long i=0;i<=n;i++) G[i].clear(); edges.clear(); } void addedge(int from,int to,long long cap,long long cost)//加边 { edges.push_back(Edge(from,to,cap,0,cost)); edges.push_back(Edge(to,from,0,0,-cost)); int m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool SPFA(int s,int t,long long &flow,long long &cost)//寻找最小费用的增广路,使用引用同时修改原flow,cost { for(int i=1;i<=n;i++) d[i] = LLONG_MAX; memset(inq,0,sizeof(inq)); d[s]=0;inq[s]=1;p[s]=0;a[s]=LLONG_MAX; queue<int> Q; Q.push(s); while(!Q.empty()) { int u=Q.front(); Q.pop(); inq[u]--; for(int i=0;i<G[u].size();i++) { Edge& e=edges[G[u][i]]; if(e.cap>e.flow && d[e.to]>d[u]+e.cost)//满足可增广且可变短 { d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]) { inq[e.to]++; Q.push(e.to); } } } } if(d[t]==LLONG_MAX) return false;//汇点不可达则退出 flow += a[t]; cost += d[t] * a[t]; int u = t; while(u != s)//更新正向边和反向边 { edges[p[u]].flow += a[t]; edges[p[u]^1].flow -= a[t]; u = edges[p[u]].from; } return true; } long long MincotMaxflow(int s,int t) { long long flow=0,cost=0; while(SPFA(s,t,flow,cost)); if(flow < 2) return -1; return cost; } }; map<string, int>m; int main(){ int t; cin >> t; while(t--){ MCMF mcmf; string a,b; long long len; int n; m.clear(); cin >> n; int N = 2 * n + 10; int cnt = 6; mcmf.init(N * 2); m["Shanghai"] = 3; mcmf.addedge(3,3 + N,2,0); m["Xian"] = 4; mcmf.addedge(4,4 + N,1,0); m["Dalian"] = 5; mcmf.addedge(5,5 + N,1,0); for(int i=0;i<n;++i){ cin >> a >> b; scanf("%lld",&len); if(m.find(a) == m.end()){ m[a] = cnt++; mcmf.addedge(m[a],m[a] + N,1,0); } if(m.find(b) == m.end()){ m[b] = cnt++; mcmf.addedge(m[b],m[b] + N,1,0); } mcmf.addedge(m[a] + N,m[b],1,len); mcmf.addedge(m[b] + N,m[a],1,len); } mcmf.addedge(1,m["Shanghai"],2,0); mcmf.addedge(m["Xian"] + N,2,1,0); mcmf.addedge(m["Dalian"] + N,2,1,0); cout << mcmf.MincotMaxflow(1,2) << endl; } return 0; }
相关文章推荐
- 计蒜客 Our Journey of Dalian Ends 最小费用最大流
- 计蒜客 16959 Our Journey of Dalian Ends(最小费用最大流-mcmf)
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 J.Our Journey of Dalian Ends【最小费用最大流】
- 计蒜客-乌鲁木齐网络赛&费用流&拆点-Our Journey of Dalian Ends
- 计蒜客 Our Journey of Dalian Ends(17新疆网赛) 费用流(思维建图)
- 计蒜客-2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛-J-Our Journey of Dalian Ends
- 计蒜客:2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛:Our Journey of Dalian Ends
- Our Journey of Dalian Ends 乌鲁木齐网络赛 最小费用最大流
- Our Journey of Dalian Ends (最小费用最大流)
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 - J Our Journey of Dalian Ends(最小费用最大流)
- 【2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛】 J Our Journey of Dalian Ends 【拆点费用流】
- 【2017新疆网络赛】Our Journey of Dalian Ends 费用流
- J: Our Journey of Dalian Ends
- Our Journey of Dalian Ends
- 计蒜客 16959 Our Journey of Dalian Ends(2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 J)
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 J. Our Journey of Dalian Ends [网络流]
- ACM ICPC 乌鲁木齐网络赛 J. Our Journey of Dalian Ends
- Our Journey of Dalian Ends【网络流】
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 [计蒜客] Our Journey of Dalian Ends
- 2017 ACM 区域赛青岛站(现场赛) K Our Journey of Xian Ends