洛谷P2050 美食节

修车加强版。发现每个厨师拆成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 \n", 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 \n", 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\n", ans);
113     return 0;
114 }
AC代码

 

posted @ 2019-03-21 18:26  huyufeifei  阅读(143)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

ReadEra 阅读书籍

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜