[CODEVS1916] 负载平衡问题(最小费用最大流)
输入所有 a[i],求出平均值 sum,每个 a[i] -= sum
那么如果 a[i] > 0,从 s 向 i 连一条容量为 a[i] 费用为 0 的有向边
如果 a[i] < 0,从 i 向 t 连一条容量为 -a[i] 费用为 0 的有向边
每个点 i 和它相邻的两个点连一条容量为 INF 费用为 1 的有向边
求出最小费用最大流即为答案
——代码
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #define INF 1e9 6 #define N 1000001 7 #define min(x, y) ((x) < (y) ? (x) : (y)) 8 9 int n, cnt, s, t; 10 int a[101], dis[N], pre[N]; 11 int head[N], to[N << 1], val[N << 1], cost[N << 1], next[N << 1]; 12 bool vis[N]; 13 14 inline int read() 15 { 16 int x = 0, f = 1; 17 char ch = getchar(); 18 for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1; 19 for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; 20 return x * f; 21 } 22 23 inline void add(int x, int y, int z, int c) 24 { 25 to[cnt] = y; 26 val[cnt] = z; 27 cost[cnt] = c; 28 next[cnt] = head[x]; 29 head[x] = cnt++; 30 } 31 32 inline bool spfa() 33 { 34 int i, u, v; 35 std::queue <int> q; 36 memset(vis, 0, sizeof(vis)); 37 memset(pre, -1, sizeof(pre)); 38 memset(dis, 127 / 3, sizeof(dis)); 39 q.push(s); 40 dis[s] = 0; 41 while(!q.empty()) 42 { 43 u = q.front(), q.pop(); 44 vis[u] = 0; 45 for(i = head[u]; i ^ -1; i = next[i]) 46 { 47 v = to[i]; 48 if(val[i] && dis[v] > dis[u] + cost[i]) 49 { 50 dis[v] = dis[u] + cost[i]; 51 pre[v] = i; 52 if(!vis[v]) 53 { 54 q.push(v); 55 vis[v] = 1; 56 } 57 } 58 } 59 } 60 return pre[t] ^ -1; 61 } 62 63 inline int dinic() 64 { 65 int i, d, sum = 0; 66 while(spfa()) 67 { 68 d = INF; 69 for(i = pre[t]; i ^ -1; i = pre[to[i ^ 1]]) d = min(d, val[i]); 70 for(i = pre[t]; i ^ -1; i = pre[to[i ^ 1]]) 71 { 72 val[i] -= d; 73 val[i ^ 1] += d; 74 } 75 sum += dis[t] * d; 76 } 77 return sum; 78 } 79 80 int main() 81 { 82 int i, j, x, sum = 0; 83 n = read(); 84 s = 0, t = n + 1; 85 memset(head, -1, sizeof(head)); 86 for(i = 1; i <= n; i++) 87 { 88 a[i] = read(); 89 sum += a[i]; 90 } 91 sum /= n; 92 for(i = 1; i <= n; i++) a[i] -= sum; 93 for(i = 1; i <= n; i++) 94 { 95 if(a[i] > 0) add(s, i, a[i], 0), add(i, s, 0, 0); 96 if(a[i] < 0) add(i, t, -a[i], 0), add(t, i, 0, 0); 97 if(i == 1) 98 { 99 add(i, 2, INF, 1), add(2, i, 0, -1); 100 add(i, n, INF, 1), add(n, i, 0, -1); 101 } 102 else if(i == n) 103 { 104 add(i, n - 1, INF, 1), add(n - 1, i, 0, -1); 105 add(i, 1, INF, 1), add(1, i, 0, -1); 106 } 107 else 108 { 109 add(i, i + 1, INF, 1), add(i + 1, i, 0, -1); 110 add(i, i - 1, INF, 1), add(i - 1, i, 0, -1); 111 } 112 } 113 printf("%d\n", dinic()); 114 return 0; 115 }