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 };

 

posted @ 2018-08-26 23:58  Ctfes  阅读(213)  评论(0编辑  收藏  举报