[codeVS1916] 负载平衡问题(最小费用流,拆点)
题目链接:http://codevs.cn/problem/1916/
n个点之间可以相互传递值,每传递一次步骤+1。最终希望所有点的值相同,问最少步骤。
最终所有值应当是平均数avg,如何在两个相邻点之间传输值?可以先拆点,再建边:
将每一个点拆成两个点(两个点集分别记为①和②),同点②到①之间的容量为inf,费用为0。
拆完点后,按照要求每一个①点连向相邻两个点的②点,容量为inf,费用为1。
需要注意的是,保证移动完每一步可以判断是否能直接流向汇点,所以要在①点集合中向汇点建边,容量为avg,费用为0。
这里建图建挫了,大致是这样:
跑最小费用流就可以了。
PS:这么看来BNU校赛的A题也可以这么建模(虽然贪心过的)。
附链接,可以思考:https://www.bnuoj.com/v3/contest_show.php?cid=9056#problem/A
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 typedef struct Node { 6 int u, v, next; 7 LL c, w; 8 }Node; 9 const int maxn = 210; 10 const int maxm = 4010; 11 const LL mod = 0x3f3f3f3fLL; 12 const LL inf = (1LL<<55); 13 int tot, head[maxn]; 14 LL dist[maxn]; 15 LL cost, flow; 16 Node e[maxm]; 17 int pre[maxn]; 18 bool visit[maxn]; 19 queue<int> Q; 20 int S, T, N; 21 22 void adde(int u, int v, LL c, LL w) { 23 e[tot].u = u; e[tot].v = v; e[tot].c = c; e[tot].w = w; e[tot].next = head[u]; head[u] = tot++; 24 e[tot].u = v; e[tot].v = u; e[tot].c = 0; e[tot].w = -w; e[tot].next = head[v]; head[v] = tot++; 25 } 26 bool spfa(int s, int t, int n) { 27 int i; 28 for(i = 0; i <= n; i++) { 29 dist[i] = inf; 30 visit[i] = 0; 31 pre[i] = -1; 32 } 33 while(!Q.empty()) Q.pop(); 34 Q.push(s); 35 visit[s] = true; 36 dist[s] = 0; 37 pre[s] = -1; 38 while(!Q.empty()) { 39 int u = Q.front(); 40 visit[u] = false; 41 Q.pop(); 42 for(int j = head[u]; j != -1; j = e[j].next) { 43 if(e[j].c > 0 && dist[u] + e[j].w < dist[e[j].v]) { 44 dist[e[j].v] = dist[u] + e[j].w; 45 pre[e[j].v] = j; 46 if(!visit[e[j].v]) { 47 Q.push(e[j].v); 48 visit[e[j].v] = true; 49 } 50 } 51 } 52 } 53 if(dist[t] == inf) return false; 54 else return true; 55 } 56 LL ChangeFlow(int t) { 57 LL det = mod; 58 int u = t; 59 while(~pre[u]) { 60 u = pre[u]; 61 det = min(det, e[u].c); 62 u = e[u].u; 63 } 64 u = t; 65 while(~pre[u]) { 66 u = pre[u]; 67 e[u].c -= det; 68 e[u ^ 1].c += det; 69 u = e[u].u; 70 } 71 return det; 72 } 73 LL MinCostFlow(int s, int t, int n) { 74 LL mincost, maxflow; 75 mincost = maxflow = 0; 76 while(spfa(s, t, n)) { 77 LL det = ChangeFlow(t); 78 mincost += det * dist[t]; 79 maxflow += det; 80 } 81 cost = mincost; 82 flow = maxflow; 83 return mincost; 84 } 85 86 int n; 87 int a[maxn]; 88 89 int main() { 90 LL avg = 0; 91 scanf("%d", &n); 92 for(int i = 1; i <= n; i++) { 93 scanf("%d", &a[i]); 94 avg += a[i]; 95 } 96 avg /= n; 97 tot = 0; 98 memset(head, -1, sizeof(head)); 99 S = 0, T = 2 * n + 1; N = T + 1; 100 for(int i = 1; i <= n; i++) { 101 adde(0, i, a[i], 0); 102 adde(i+n, i, inf, 0); 103 adde(i, T, (LL)avg, 0); 104 } 105 for(int i = 1; i < n; i++) adde(i, i+n+1, inf, 1); 106 adde(n, n+1, inf, 1); 107 for(int i = 2; i <= n; i++) adde(i, i+n-1, inf, 1); 108 adde(1, 2*n, inf, 1); 109 cout << MinCostFlow(S, T, N) << endl; 110 return 0; 111 }