UVa 1658 - Admiral(最小费用最大流 + 拆点)
链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4533
题意:
给出一个v(3≤v≤1000)个点e(3≤e≤10000)条边的有向加权图,
求1~v的两条不相交(除了起点和终点外没有公共点)的路径,使得权和最小。
分析:
把2到v-1的每个结点i拆成i和i'两个结点,中间连一条容量为1,费用为0的边,然后求1到v的流量为2的最小费用流即可。
本题的拆点法是解决结点容量的通用方法。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <vector> 5 using namespace std; 6 7 /// 结点下标从0开始,注意maxn 8 struct MCMF { 9 static const int maxn = 1000 * 2 + 5; 10 static const int INF = 0x3f3f3f3f; 11 struct Edge { 12 int from, to, cap, flow, cost; 13 }; 14 15 int n, m; 16 vector<Edge> edges; 17 vector<int> G[maxn]; 18 int inq[maxn]; // 是否在队列中 19 int d[maxn]; // Bellman-Ford 20 int p[maxn]; // 上一条弧 21 int a[maxn]; // 可改进量 22 23 void init(int n) { 24 this->n = n; 25 for(int i = 0; i < n; i++) G[i].clear(); 26 edges.clear(); 27 } 28 void AddEdge(int from, int to, int cap, int cost) { 29 edges.push_back((Edge){from, to, cap, 0, cost}); 30 edges.push_back((Edge){to, from, 0, 0, -cost}); 31 m = edges.size(); 32 G[from].push_back(m-2); 33 G[to].push_back(m-1); 34 } 35 bool BellmanFord(int s, int t, int flow_limit, int& flow, int& cost) { 36 for(int i = 0; i < n; i++) d[i] = INF; 37 memset(inq, 0, sizeof(inq)); 38 d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF; 39 queue<int> Q; 40 Q.push(s); 41 while(!Q.empty()) { 42 int u = Q.front(); Q.pop(); 43 inq[u] = 0; 44 for(int i = 0; i < G[u].size(); i++) { 45 Edge& e = edges[G[u][i]]; 46 if(e.cap > e.flow && d[e.to] > d[u] + e.cost) { 47 d[e.to] = d[u] + e.cost; 48 p[e.to] = G[u][i]; 49 a[e.to] = min(a[u], e.cap - e.flow); 50 if(!inq[e.to]) { 51 Q.push(e.to); 52 inq[e.to] = 1; 53 } 54 } 55 } 56 } 57 if(d[t] == INF) return false; 58 if(flow + a[t] > flow_limit) a[t] = flow_limit - flow; 59 flow += a[t]; 60 cost += d[t] * a[t]; 61 for(int u = t; u != s; u = edges[p[u]].from) { 62 edges[p[u]].flow += a[t]; 63 edges[p[u]^1].flow -= a[t]; 64 } 65 return true; 66 } 67 // 需要保证初始网络中没有负权圈 68 int MincostMaxflow(int s, int t, int flow_limit) { 69 int flow = 0, cost = 0; 70 //while(BellmanFord(s, t, flow, cost)); 71 while(flow < flow_limit && BellmanFord(s, t, flow_limit, flow, cost)); 72 return cost; 73 } 74 }; 75 76 MCMF mc; 77 78 int main() { 79 int v, e; 80 while(~scanf("%d%d", &v, &e)) { 81 mc.init(v*2-2); 82 for(int i = 1; i < v-1; i++) mc.AddEdge(i, i+v-1, 1, 0); 83 for(int a, b, c, i = 0; i < e; i++) { 84 scanf("%d%d%d", &a, &b, &c); 85 a = (a == 1 || a == v) ? a-1 : a+v-2; 86 b--; 87 mc.AddEdge(a, b, 1, c); 88 } 89 printf("%d\n", mc.MincostMaxflow(0, v-1, 2)); 90 } 91 return 0; 92 }
最小费用最大流模板:
1 /// 结点下标从0开始,注意maxn 2 struct MCMF { 3 static const int maxn = 1e3 + 5; 4 static const int INF = 0x3f3f3f3f; 5 struct Edge { 6 int from, to, cap, flow, cost; 7 }; 8 9 int n, m; 10 vector<Edge> edges; 11 vector<int> G[maxn]; 12 int inq[maxn]; // 是否在队列中 13 int d[maxn]; // Bellman-Ford 14 int p[maxn]; // 上一条弧 15 int a[maxn]; // 可改进量 16 17 void init(int n) { 18 this->n = n; 19 for(int i = 0; i < n; i++) G[i].clear(); 20 edges.clear(); 21 } 22 void AddEdge(int from, int to, int cap, int cost) { 23 edges.push_back((Edge){from, to, cap, 0, cost}); 24 edges.push_back((Edge){to, from, 0, 0, -cost}); 25 m = edges.size(); 26 G[from].push_back(m-2); 27 G[to].push_back(m-1); 28 } 29 bool BellmanFord(int s, int t, int& flow, int& cost) { 30 for(int i = 0; i < n; i++) d[i] = INF; 31 memset(inq, 0, sizeof(inq)); 32 d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF; 33 queue<int> Q; 34 Q.push(s); 35 while(!Q.empty()) { 36 int u = Q.front(); Q.pop(); 37 inq[u] = 0; 38 for(int i = 0; i < G[u].size(); i++) { 39 Edge& e = edges[G[u][i]]; 40 if(e.cap > e.flow && d[e.to] > d[u] + e.cost) { 41 d[e.to] = d[u] + e.cost; 42 p[e.to] = G[u][i]; 43 a[e.to] = min(a[u], e.cap - e.flow); 44 if(!inq[e.to]) { 45 Q.push(e.to); 46 inq[e.to] = 1; 47 } 48 } 49 } 50 } 51 if(d[t] == INF) return false; 52 //if(flow + a[t] > flow_limit) a[t] = flow_limit - flow; 53 flow += a[t]; 54 cost += d[t] * a[t]; 55 for(int u = t; u != s; u = edges[p[u]].from) { 56 edges[p[u]].flow += a[t]; 57 edges[p[u]^1].flow -= a[t]; 58 } 59 return true; 60 } 61 // 需要保证初始网络中没有负权圈 62 int MincostMaxflow(int s, int t) { 63 int flow = 0, cost = 0; 64 while(BellmanFord(s, t, flow, cost)); 65 //while(flow < flow_limit && BellmanFord(s, t, flow_limit, flow, cost)); 66 return cost; 67 } 68 };