修车加强版。发现每个厨师拆成p个点太浪费了,毕竟总共用到的才p个点。于是从下往上一个一个加,加到满流就停。
论动态加点费用流的正确姿势......
我自己加总是出现负环...我是每次加一整层,然后跑完这一层再加下一层,这样会显而易见的出现负环......
然后我们发现如果每增广一流量就加边就不会出现这种毒瘤现象,因为每次加的一定比增广的劣......
注意一定要动态开点,不能只用一个点代表厨师。否则可能出现厨师的第一次给了多个菜的情况...
1 #include <bits/stdc++.h> 2 3 const int N = 100010, INF = 0x7f7f7f7f; 4 5 struct Edge { 6 int nex, v, c, len; 7 Edge(int Nex = 0, int V = 0, int C = 0, int Len = 0) { 8 nex = Nex; 9 v = V; 10 c = C; 11 len = Len; 12 } 13 }edge[5000010]; int tp = 1; 14 15 int e[N], lm, now[N], pre[N], flow[N], p[N], cnt[N], d[N]; 16 int val[110][110]; 17 bool vis[N]; 18 std::queue<int> Q; 19 20 inline void add(int x, int y, int z, int w) { 21 edge[++tp] = Edge(e[x], y, z, w); 22 e[x] = tp; 23 edge[++tp] = Edge(e[y], x, 0, -w); 24 e[y] = tp; 25 return; 26 } 27 28 inline bool SPFA(int s, int t) { 29 memset(d + 1, 0x7f, lm * sizeof(int)); 30 vis[s] = 1; 31 flow[s] = INF; 32 d[s] = 0; 33 Q.push(s); 34 while(!Q.empty()) { 35 int x = Q.front(); 36 Q.pop(); 37 vis[x] = 0; 38 for(int i = e[x]; i; i = edge[i].nex) { 39 int y = edge[i].v; 40 if(d[y] > d[x] + edge[i].len && edge[i].c) { 41 d[y] = d[x] + edge[i].len; 42 //printf("%d -> %d ", x, y); 43 flow[y] = std::min(flow[x], edge[i].c); 44 pre[y] = i; 45 if(!vis[y]) { 46 vis[y] = 1; 47 Q.push(y); 48 } 49 } 50 } 51 } 52 return d[t] < INF; 53 } 54 55 inline void update(int s, int t) { 56 int f = flow[t]; 57 while(t != s) { 58 int i = pre[t]; 59 edge[i].c -= f; 60 edge[i ^ 1].c += f; 61 t = edge[i ^ 1].v; 62 } 63 return; 64 } 65 66 int main() { 67 68 int n, m, tot = 0; 69 scanf("%d%d", &n, &m); 70 lm = n; 71 int s = ++lm; 72 int t = ++lm; 73 for(int i = 1; i <= n; i++) { 74 scanf("%d", &p[i]); 75 add(s, i, p[i], 0); 76 tot += p[i]; 77 } 78 for(int i = 1; i <= n; i++) { 79 for(int j = 1; j <= m; j++) { 80 scanf("%d", &val[i][j]); 81 } 82 } 83 /// sol 84 for(int i = 1; i <= m; i++) { 85 add(++lm, t, 1, 0); 86 cnt[i] = 1; 87 now[i] = tp - 1; 88 for(int j = 1; j <= n; j++) { 89 add(j, lm, 1, val[j][i]); 90 } 91 } 92 93 int ans = 0; 94 while(tot) { 95 //printf("tot = %d ans = %d ", tot, ans); 96 SPFA(s, t); 97 ans += d[t] * flow[t]; 98 tot -= flow[t]; 99 update(s, t); 100 for(int j = 1; j <= m; j++) { 101 if(edge[now[j]].c) continue; 102 add(++lm, t, 1, 0); 103 now[j] = tp - 1; 104 cnt[j]++; 105 for(int i = 1; i <= n; i++) { 106 add(i, lm, 1, cnt[j] * val[i][j]); 107 } 108 break; 109 } 110 } 111 112 printf("%d ", ans); 113 return 0; 114 }