题意:有m个人,给定n个城市构成DAG。
每个城市恰好有vi个人经过,每条边有费用。
每个人自选起点,终点。
求最小费用。
解:
首先拆点,连边,流量为[vi, vi]。
然后做有上下界有源汇最小费用可行流即可。
1 #include <cstdio> 2 #include <algorithm> 3 #include <queue> 4 #include <cstring> 5 #include <cmath> 6 7 const int N = 18000, M = 1000010, INF = 0x3f3f3f3f; 8 9 struct Edge { 10 int nex, v, c, len; 11 }edge[M << 1]; int top = 1; 12 13 int e[N], d[N], vis[N], pre[N], flow[N]; 14 std::queue<int> Q; 15 bool vp[200010]; 16 17 inline void add(int x, int y, int z, int w) { 18 top++; 19 edge[top].v = y; 20 edge[top].c = z; 21 edge[top].len = w; 22 edge[top].nex = e[x]; 23 e[x] = top; 24 25 top++; 26 edge[top].v = x; 27 edge[top].c = 0; 28 edge[top].len = -w; 29 edge[top].nex = e[y]; 30 e[y] = top; 31 return; 32 } 33 34 inline bool SPFA(int s, int t) { 35 memset(d, 0x3f, sizeof(d)); 36 d[s] = 0; 37 flow[s] = INF; 38 vis[s] = 1; 39 Q.push(s); 40 while(!Q.empty()) { 41 int x = Q.front(); 42 Q.pop(); 43 vis[x] = 0; 44 for(int i = e[x]; i; i = edge[i].nex) { 45 int y = edge[i].v; 46 if(edge[i].c && d[y] > d[x] + edge[i].len) { 47 d[y] = d[x] + edge[i].len; 48 pre[y] = i; 49 flow[y] = std::min(flow[x], edge[i].c); 50 if(!vis[y]) { 51 vis[y] = 1; 52 Q.push(y); 53 } 54 } 55 } 56 } 57 return d[t] < INF; 58 } 59 60 inline void update(int s, int t) { 61 int temp = flow[t]; 62 while(t != s) { 63 int i = pre[t]; 64 edge[i].c -= temp; 65 edge[i ^ 1].c += temp; 66 t = edge[i ^ 1].v; 67 } 68 return; 69 } 70 71 inline int solve(int s, int t, int &cost) { 72 int ans = 0; 73 cost = 0; 74 while(SPFA(s, t)) { 75 ans += flow[t]; 76 cost += flow[t] * d[t]; 77 update(s, t); 78 } 79 return ans; 80 } 81 82 83 int main() { 84 85 int n, m; 86 scanf("%d%d", &n, &m); 87 int s = 2 * n + 1, t = 2 * n + 2, ss = 2 * n + 3, S = n * 2 + 4, T = n * 2 + 5; 88 for(int i = 1, x; i <= n; i++) { 89 scanf("%d", &x); 90 // add i i + n x 91 add(S, i + n, x, 0); 92 add(i, T, x, 0); 93 } 94 for(int i = 1, x; i <= n; i++) { 95 for(int j = i + 1; j <= n; j++) { 96 scanf("%d", &x); 97 if(x == -1) { 98 continue; 99 } 100 add(i + n, j, INF, x); 101 } 102 add(ss, i, INF, 0); 103 add(i + n, t, INF, 0); 104 } 105 add(s, ss, m, 0); 106 add(t, s, INF, 0); 107 int ans; 108 solve(S, T, ans); 109 printf("%d", ans); 110 return 0; 111 }