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

 

posted @ 2017-04-26 14:22  Kirai  阅读(116)  评论(0编辑  收藏  举报