zoukankan      html  css  js  c++  java
  • 最小割

    复习一波最小割...

    理论知识:

    参考资料

    BZOJ1934 善意的投票

    题意:n个人分别喜欢睡/不睡午觉。改变一个人的喜好要花费1代价。有m对朋友,每对朋友的喜好不同会产生1代价。求最小代价。

    解:经典题了.....

    每个人向s,t连边,求最小割。如果割掉某个边就代表选哪边。朋友之间连双向边,代表如果选的不同的话还要割一刀。

    考虑为什么不会有点两条边都被割。因为两条边都被割表明有个跟它相连的没割上面,又有个跟它相连的没割下面,而这显然是不可能的,因为它们会通过这个点间接的出现一条流。

     1 #include <bits/stdc++.h>
     2 
     3 const int N = 3010, INF = 0x3f3f3f3f;
     4 
     5 struct Edge {
     6     int nex, v, c;
     7     Edge(int NEX = 0, int V = 0, int C = 0) {
     8         nex = NEX;
     9         v = V;
    10         c = C;
    11     }
    12 }edge[2000010]; int tp = 1;
    13 
    14 int e[N], d[N], vis[N], Time, cur[N], cnt;
    15 std::queue<int> Q;
    16 int n, a[N];
    17 
    18 inline void add(int x, int y, int z) {
    19     edge[++tp] = Edge(e[x], y, z);
    20     e[x] = tp;
    21     edge[++tp] = Edge(e[y], x, 0);
    22     e[y] = tp;
    23     return;
    24 }
    25 
    26 inline bool BFS(int s, int t) {
    27     Time++;
    28     vis[s] = Time;
    29     d[s] = 0;
    30     Q.push(s);
    31     while(Q.size()) {
    32         int x = Q.front();
    33         Q.pop();
    34         for(int i = e[x]; i; i = edge[i].nex) {
    35             int y = edge[i].v;
    36             if(vis[y] == Time || !edge[i].c) continue;
    37             vis[y] = Time;
    38             d[y] = d[x] + 1;
    39             Q.push(y);
    40         }
    41     }
    42     return vis[t] == Time;
    43 }
    44 
    45 int DFS(int x, int t, int maxF) {
    46     if(x == t) return maxF;
    47     int ans = 0;
    48     for(int i = cur[x]; i; i = edge[i].nex) {
    49         int y = edge[i].v;
    50         if(d[y] != d[x] + 1 || !edge[i].c) continue;
    51         int temp = DFS(y, t, std::min(edge[i].c, maxF - ans));
    52         if(!temp) d[y] = INF;
    53         ans += temp;
    54         edge[i].c -= temp;
    55         edge[i ^ 1].c += temp;
    56         if(ans == maxF) break;
    57         cur[x] = i;
    58     }
    59     return ans;
    60 }
    61 
    62 inline int solve(int s, int t) {
    63     int ans = 0;
    64     while(BFS(s, t)) {
    65         memcpy(cur + 1, e + 1, cnt * sizeof(int));
    66         ans += DFS(s, t, INF);
    67     }
    68     return ans;
    69 }
    70 
    71 int main() {
    72     int m;
    73     scanf("%d%d", &n, &m);
    74     int s = n + 1, t = n + 2;
    75     cnt = t;
    76     for(int i = 1; i <= n; i++) {
    77         scanf("%d", &a[i]);
    78         if(a[i]) {
    79             add(s, i, 1);
    80         }
    81         else {
    82             add(i, t, 1);
    83         }
    84     }
    85     for(int i = 1, x, y; i <= m; i++) {
    86         scanf("%d%d", &x, &y);
    87         add(x, y, 1);
    88         add(y, x, 1);
    89     }
    90     int ans = solve(s, t);
    91     printf("%d
    ", ans);
    92     return 0;
    93 }
    AC代码

    BZOJ2127 happiness

    题意:n个人,m对朋友。每个人选文科,理科都分别有贡献,每对朋友同时选文/选理也有贡献。求最大贡献。

    解:先设每个人同时选了文理。考虑割掉。

    s向人连选文的贡献,人向t连选理的。一对朋友之间,考虑到如果有任一个选了文,就拿不到全选理的贡献,所以建图大概长这样...

    然后求最小割,拿总贡献减去,就是最大贡献了。

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 100010, INF = 0x3f3f3f3f;
      4 
      5 struct Edge {
      6     int nex, v, c;
      7     Edge(int NEX = 0, int V = 0, int C = 0) {
      8         nex = NEX;
      9         v = V;
     10         c = C;
     11     }
     12 }edge[2000010]; int tp = 1;
     13 
     14 int e[N], d[N], vis[N], Time, cur[N], cnt;
     15 std::queue<int> Q;
     16 int n, m, s, t;
     17 
     18 inline void add(int x, int y, int z) {
     19     edge[++tp] = Edge(e[x], y, z);
     20     e[x] = tp;
     21     edge[++tp] = Edge(e[y], x, 0);
     22     e[y] = tp;
     23     return;
     24 }
     25 
     26 inline bool BFS(int s, int t) {
     27     Time++;
     28     vis[s] = Time;
     29     d[s] = 0;
     30     Q.push(s);
     31     while(Q.size()) {
     32         int x = Q.front();
     33         Q.pop();
     34         for(int i = e[x]; i; i = edge[i].nex) {
     35             int y = edge[i].v;
     36             if(vis[y] == Time || !edge[i].c) continue;
     37             vis[y] = Time;
     38             d[y] = d[x] + 1;
     39             Q.push(y);
     40         }
     41     }
     42     return vis[t] == Time;
     43 }
     44 
     45 int DFS(int x, int t, int maxF) {
     46     if(x == t) return maxF;
     47     int ans = 0;
     48     for(int i = cur[x]; i; i = edge[i].nex) {
     49         int y = edge[i].v;
     50         if(d[y] != d[x] + 1 || !edge[i].c) continue;
     51         int temp = DFS(y, t, std::min(edge[i].c, maxF - ans));
     52         if(!temp) d[y] = INF;
     53         ans += temp;
     54         edge[i].c -= temp;
     55         edge[i ^ 1].c += temp;
     56         if(ans == maxF) break;
     57         cur[x] = i;
     58     }
     59     return ans;
     60 }
     61 
     62 inline int solve(int s, int t) {
     63     int ans = 0;
     64     while(BFS(s, t)) {
     65         memcpy(cur + 1, e + 1, cnt * sizeof(int));
     66         ans += DFS(s, t, INF);
     67     }
     68     return ans;
     69 }
     70 
     71 inline int id(int i, int j) {
     72     return (i - 1) * m + j;
     73 }
     74 
     75 int main() {
     76     scanf("%d%d", &n, &m);
     77     s = n * m + 1, t = s + 1;
     78     int ans = 0, x;
     79     cnt = t;
     80     for(int i = 1; i <= n; i++) {
     81         for(int j = 1; j <= m; j++) {
     82             scanf("%d", &x);
     83             ans += x;
     84             add(s, id(i, j), x);
     85         }
     86     }
     87     for(int i = 1; i <= n; i++) {
     88         for(int j = 1; j <= m; j++) {
     89             scanf("%d", &x);
     90             ans += x;
     91             add(id(i, j), t, x);
     92         }
     93     }
     94     for(int i = 1; i < n; i++) {
     95         for(int j = 1; j <= m; j++) {
     96             scanf("%d", &x);
     97             ans += x;
     98             add(s, ++cnt, x);
     99             add(cnt, id(i, j), INF);
    100             add(cnt, id(i + 1, j), INF);
    101         }
    102     }
    103     for(int i = 1; i < n; i++) {
    104         for(int j = 1; j <= m; j++) {
    105             scanf("%d", &x);
    106             ans += x;
    107             add(++cnt, t, x);
    108             add(id(i, j), cnt, INF);
    109             add(id(i + 1, j), cnt, INF);
    110         }
    111     }
    112     for(int i = 1; i <= n; i++) {
    113         for(int j = 1; j < m; j++) {
    114             scanf("%d", &x);
    115             ans += x;
    116             add(s, ++cnt, x);
    117             add(cnt, id(i, j), INF);
    118             add(cnt, id(i, j + 1), INF);
    119         }
    120     }
    121     for(int i = 1; i <= n; i++) {
    122         for(int j = 1; j < m; j++) {
    123             scanf("%d", &x);
    124             ans += x;
    125             add(++cnt, t, x);
    126             add(id(i, j), cnt, INF);
    127             add(id(i, j + 1), cnt, INF);
    128         }
    129     }
    130     ans -= solve(s, t);
    131     printf("%d
    ", ans);
    132     return 0;
    133 }
    AC代码

    注意这题建图画风跟别的题不一样,是因为按照之前的建图,当一对朋友同时选0的时候,仍要损失同时选1的代价,而这部分是我们难以计算的。

    BZOJ1976 能量魔方

    题意:有n3个块构成了立方体,有些位置填了0/1,别的地方自己填。6连通的块之间如果颜色不同就会有1贡献,求最大贡献。

    解:前两题都是最大化相同,最小化不同,这题反其道而行之,何如?

    考虑到这些格子和6连通关系构成了二分图。我们把其中一个部分全部反色,不就成了最大化相同吗?直接套用第一题的做法。

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 100010, INF = 0x3f3f3f3f;
      4 
      5 struct Edge {
      6     int nex, v, c;
      7     Edge(int NEX = 0, int V = 0, int C = 0) {
      8         nex = NEX;
      9         v = V;
     10         c = C;
     11     }
     12 }edge[2000010]; int tp = 1;
     13 
     14 int e[N], d[N], vis[N], Time, cur[N], cnt;
     15 std::queue<int> Q;
     16 int n;
     17 
     18 inline void add(int x, int y, int z) {
     19     edge[++tp] = Edge(e[x], y, z);
     20     e[x] = tp;
     21     edge[++tp] = Edge(e[y], x, 0);
     22     e[y] = tp;
     23     return;
     24 }
     25 
     26 inline bool BFS(int s, int t) {
     27     Time++;
     28     vis[s] = Time;
     29     d[s] = 0;
     30     Q.push(s);
     31     while(Q.size()) {
     32         int x = Q.front();
     33         Q.pop();
     34         for(int i = e[x]; i; i = edge[i].nex) {
     35             int y = edge[i].v;
     36             if(vis[y] == Time || !edge[i].c) continue;
     37             vis[y] = Time;
     38             d[y] = d[x] + 1;
     39             Q.push(y);
     40         }
     41     }
     42     return vis[t] == Time;
     43 }
     44 
     45 int DFS(int x, int t, int maxF) {
     46     if(x == t) return maxF;
     47     int ans = 0;
     48     for(int i = cur[x]; i; i = edge[i].nex) {
     49         int y = edge[i].v;
     50         if(d[y] != d[x] + 1 || !edge[i].c) continue;
     51         int temp = DFS(y, t, std::min(edge[i].c, maxF - ans));
     52         if(!temp) d[y] = INF;
     53         ans += temp;
     54         edge[i].c -= temp;
     55         edge[i ^ 1].c += temp;
     56         if(ans == maxF) break;
     57         cur[x] = i;
     58     }
     59     return ans;
     60 }
     61 
     62 inline int solve(int s, int t) {
     63     int ans = 0;
     64     while(BFS(s, t)) {
     65         memcpy(cur + 1, e + 1, cnt * sizeof(int));
     66         ans += DFS(s, t, INF);
     67     }
     68     return ans;
     69 }
     70 
     71 inline int id(int x, int y, int z) {
     72     return (x - 1) * n * n + (y - 1) * n + z;
     73 }
     74 
     75 char str[N];
     76 
     77 int main() {
     78     scanf("%d", &n);
     79     int s = n * n * n + 1, t = s + 1, ans = 0;
     80     cnt = t;
     81     for(int i = 1; i <= n; i++) {
     82         for(int j = 1; j <= n; j++) {
     83             scanf("%s", str + 1);
     84             for(int k = 1; k <= n; k++) {
     85                 if(str[k] == '?');
     86                 else if((str[k] == 'P') == ((i + j + k) & 1)) {
     87                     add(s, id(i, j, k), INF);
     88                 }
     89                 else {
     90                     add(id(i, j, k), t, INF);
     91                 }
     92 
     93                 if(i > 1) {
     94                     add(id(i, j, k), id(i - 1, j, k), 1);
     95                     add(id(i - 1, j, k), id(i, j, k), 1);
     96                     ans++;
     97                 }
     98                 if(j > 1) {
     99                     add(id(i, j, k), id(i, j - 1, k), 1);
    100                     add(id(i, j - 1, k), id(i, j, k), 1);
    101                     ans++;
    102                 }
    103                 if(k > 1) {
    104                     add(id(i, j, k), id(i, j, k - 1), 1);
    105                     add(id(i, j, k - 1), id(i, j, k), 1);
    106                     ans++;
    107                 }
    108             }
    109         }
    110     }
    111     printf("%d
    ", ans - solve(s, t));
    112     return 0;
    113 }
    AC代码

    BZOJ2132 圈地计划

    题意:给你一个矩阵,每个位置放0有贡献,放1有贡献,4连通的格子放不同的还有贡献,求最大贡献。

    解:类似上一题,黑白染色之后把黑色格子放的全部反转,就有相同相邻的格子会产生贡献。注意01分别的贡献也要相应的反转。

    然后使用上一题的做法即可。

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 100010, INF = 0x3f3f3f3f;
      4 
      5 struct Edge {
      6     int nex, v, c;
      7     Edge(int NEX = 0, int V = 0, int C = 0) {
      8         nex = NEX;
      9         v = V;
     10         c = C;
     11     }
     12 }edge[2000010]; int tp = 1;
     13 
     14 int e[N], d[N], vis[N], Time, cur[N], cnt;
     15 std::queue<int> Q;
     16 int n, m, a[101][101], b[101][101], c[101][101];
     17 
     18 inline void add(int x, int y, int z) {
     19     edge[++tp] = Edge(e[x], y, z);
     20     e[x] = tp;
     21     edge[++tp] = Edge(e[y], x, 0);
     22     e[y] = tp;
     23     return;
     24 }
     25 
     26 inline bool BFS(int s, int t) {
     27     Time++;
     28     vis[s] = Time;
     29     d[s] = 0;
     30     Q.push(s);
     31     while(Q.size()) {
     32         int x = Q.front();
     33         Q.pop();
     34         for(int i = e[x]; i; i = edge[i].nex) {
     35             int y = edge[i].v;
     36             if(vis[y] == Time || !edge[i].c) continue;
     37             vis[y] = Time;
     38             d[y] = d[x] + 1;
     39             Q.push(y);
     40         }
     41     }
     42     return vis[t] == Time;
     43 }
     44 
     45 int DFS(int x, int t, int maxF) {
     46     if(x == t) return maxF;
     47     int ans = 0;
     48     for(int i = cur[x]; i; i = edge[i].nex) {
     49         int y = edge[i].v;
     50         if(d[y] != d[x] + 1 || !edge[i].c) continue;
     51         int temp = DFS(y, t, std::min(edge[i].c, maxF - ans));
     52         if(!temp) d[y] = INF;
     53         ans += temp;
     54         edge[i].c -= temp;
     55         edge[i ^ 1].c += temp;
     56         if(ans == maxF) break;
     57         cur[x] = i;
     58     }
     59     return ans;
     60 }
     61 
     62 inline int solve(int s, int t) {
     63     int ans = 0;
     64     while(BFS(s, t)) {
     65         memcpy(cur + 1, e + 1, cnt * sizeof(int));
     66         ans += DFS(s, t, INF);
     67     }
     68     return ans;
     69 }
     70 
     71 inline int id(int i, int j) {
     72     return (i - 1) * m + j;
     73 }
     74 
     75 int main() {
     76     scanf("%d%d", &n, &m);
     77     int s = n * m + 1, t = s + 1, ans = 0;
     78     cnt = t;
     79     for(int i = 1; i <= n; i++) {
     80         for(int j = 1; j <= m; j++) {
     81             scanf("%d", &a[i][j]);
     82             ans += a[i][j];
     83         }
     84     }
     85     for(int i = 1; i <= n; i++) {
     86         for(int j = 1; j <= m; j++) {
     87             scanf("%d", &b[i][j]);
     88             ans += b[i][j];
     89             if((i + j) & 1) {
     90                 std::swap(a[i][j], b[i][j]);
     91             }
     92             add(s, id(i, j), a[i][j]);
     93             add(id(i, j), t, b[i][j]);
     94         }
     95     }
     96     for(int i = 1; i <= n; i++) {
     97         for(int j = 1; j <= m; j++) {
     98             scanf("%d", &c[i][j]);
     99             if(i > 1) {
    100                 add(id(i, j), id(i - 1, j), c[i][j] + c[i - 1][j]);
    101                 add(id(i - 1, j), id(i, j), c[i][j] + c[i - 1][j]);
    102                 ans += c[i][j] + c[i - 1][j];
    103             }
    104             if(j > 1) {
    105                 add(id(i, j), id(i, j - 1), c[i][j] + c[i][j - 1]);
    106                 add(id(i, j - 1), id(i, j), c[i][j] + c[i][j - 1]);
    107                 ans += c[i][j] + c[i][j - 1];
    108             }
    109         }
    110     }
    111 
    112     printf("%d
    ", ans - solve(s, t));
    113 
    114     return 0;
    115 }
    AC代码

    LOJ#2146 寿司餐厅

    题意:有个寿司序列,每个子串都有个价值,每个寿司有个种类。你可以无限次的取,每次取一个子串,那么就能得到这个子串的所有子串的贡献。但是每个子串[l, r]的贡献不管取了多少次都只会算一次。如果最终这n个寿司中你吃到过其中i(i > 0)个x种类的寿司,那么就要付出m * x * x + i * x的钱。求你能得到的最大(总价值 - 钱数)。

    解:在那想50分状压怎么做,结果想着就把正解搞出来了,状压还是不会...

    画出矩形来,发现每次就是取一个左下角的前缀和,相当于取了一个点就要取它左下的所有点。这是最大权闭合子图。然后怎么算付的钱呢?每个寿司(就是i,i那个位置)连到一个(-x)的点。然后所有(-x)的点再连到一个(-x2)的点即可。

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 110, M = 100010, INF = 0x3f3f3f3f;
      4 
      5 struct Edge {
      6     int nex, v, c;
      7     Edge(int NEX = 0, int V = 0, int C = 0) {
      8         nex = NEX;
      9         v = V;
     10         c = C;
     11     }
     12 }edge[2000010]; int tp = 1;
     13 
     14 int e[M], a[N], d[N][N], n, m, val[M], dis[M], vis[M], Time, cnt, cur[M], id[N][N], use[1010];
     15 std::queue<int> Q;
     16 
     17 inline void add(int x, int y, int z) {
     18     //printf("add %d %d %d 
    ", x, y, z);
     19     edge[++tp] = Edge(e[x], y, z);
     20     e[x] = tp;
     21     edge[++tp] = Edge(e[y], x, 0);
     22     e[y] = tp;
     23     return;
     24 }
     25 
     26 inline bool BFS(int s, int t) {
     27     Time++;
     28     vis[s] = Time;
     29     dis[s] = 0;
     30     Q.push(s);
     31     while(Q.size()) {
     32         int x = Q.front();
     33         Q.pop();
     34         //printf("BFS x = %d 
    ", x);
     35         for(int i = e[x]; i; i = edge[i].nex) {
     36             int y = edge[i].v;
     37             if(vis[y] == Time || !edge[i].c) {
     38                 continue;
     39             }
     40             //printf("BFS %d -> %d 
    ", x, y);
     41             vis[y] = Time;
     42             dis[y] = dis[x] + 1;
     43             Q.push(y);
     44         }
     45     }
     46     return vis[t] == Time;
     47 }
     48 
     49 int DFS(int x, int t, int maxF) {
     50     if(x == t) {
     51         //printf("x == t maxF = %d 
    ", maxF);
     52         return maxF;
     53     }
     54     int ans = 0;
     55     for(int i = cur[x]; i; i = edge[i].nex) {
     56         int y = edge[i].v;
     57         if(dis[y] != dis[x] + 1 || !edge[i].c) continue;
     58         int temp = DFS(y, t, std::min(maxF - ans, edge[i].c));
     59         //printf("DFS %d -> %d  min %d %d  
    ", x, y, maxF - ans, edge[i].c);
     60         if(!temp) dis[y] = INF;
     61         ans += temp;
     62         edge[i].c -= temp;
     63         edge[i ^ 1].c += temp;
     64         if(ans == maxF) break;
     65         cur[x] = i;
     66     }
     67     return ans;
     68 }
     69 
     70 inline int solve(int s, int t) {
     71     int ans = 0;
     72     while(BFS(s, t)) {
     73         memcpy(cur + 1, e + 1, cnt * sizeof(int));
     74         //int temp = DFS(s, t, INF);
     75         //printf("ans += %d 
    ", temp);
     76         ans += DFS(s, t, INF);
     77 
     78     }
     79     return ans;
     80 }
     81 
     82 inline bool valid(int x, int y) {
     83     if(!x || !y || x > n || y > n) return false;
     84     return y >= x;
     85 }
     86 
     87 int main() {
     88     scanf("%d%d", &n, &m);
     89     int s = 1, t = 2, ans = 0;
     90     cnt = t;
     91     for(int i = 1; i <= n; i++) {
     92         scanf("%d", &a[i]);
     93     }
     94     for(int i = 1; i <= n; i++) {
     95         for(int j = i; j <= n; j++) {
     96             scanf("%d", &d[i][j]);
     97             id[i][j] = ++cnt;
     98             if(d[i][j] > 0) {
     99                 add(s, id[i][j], d[i][j]);
    100                 ans += d[i][j];
    101             }
    102             else if(d[i][j] < 0) {
    103                 add(id[i][j], t, -d[i][j]);
    104             }
    105             if(valid(i, j - 1)) {
    106                 add(id[i][j], id[i][j - 1], INF);
    107             }
    108             if(valid(i - 1, j)) {
    109                 add(id[i - 1][j], id[i][j], INF);
    110             }
    111         }
    112         add(id[i][i], ++cnt, INF);
    113         add(cnt, t, a[i]);
    114         if(m) {
    115             if(!use[a[i]]) {
    116                 use[a[i]] = ++cnt;
    117                 add(cnt - 1, cnt, INF);
    118                 add(cnt, t, a[i] * a[i]);
    119             }
    120             else {
    121                 add(cnt, use[a[i]], INF);
    122             }
    123         }
    124     }
    125 
    126     printf("%d", ans - solve(s, t));
    127     return 0;
    128 }
    AC代码

    去膜了一下官方题解,发现这SB题没有状压做法......当m = 0的时候可以直接区间DP预处理每一段全选的最大价值,然后再在序列上按照断点DP。

    如果能够重复计算一个子串的贡献呢?不会......

    BZOJ3996 线性代数

    题意:给出一个N * N的矩阵B和一个1 * N的矩阵C。求出一个1 * N的01矩阵A,使得D = (A * B - C) * AT最大。输出D。

    解:暴力推一波式子,发现D = ∑(∑(AiAjBij) - AiCi),由于A是01矩阵,所以相当于选出若干个B,如果Bij被选,那么-Ci和-Cj也会被选。求最大价值。最大权闭合子图。

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 260010, INF = 0x3f3f3f3f;
      4 
      5 struct Edge {
      6     int nex, v, c;
      7     Edge(int NEX = 0, int V = 0, int C = 0) {
      8         nex = NEX;
      9         v = V;
     10         c = C;
     11     }
     12 }edge[2000010]; int tp = 1;
     13 
     14 int e[N], cur[N], d[N], vis[N], Time, cnt, n;
     15 std::queue<int> Q;
     16 
     17 inline void add(int x, int y, int z) {
     18     //printf("add %d %d 
    ", x, y);
     19     edge[++tp] = Edge(e[x], y, z);
     20     e[x] = tp;
     21     edge[++tp] = Edge(e[y], x, 0);
     22     e[y] = tp;
     23     return;
     24 }
     25 
     26 inline bool BFS(int s, int t) {
     27     Time++;
     28     vis[s] = Time;
     29     d[s] = 0;
     30     Q.push(s);
     31     while(Q.size()) {
     32         int x = Q.front();
     33         Q.pop();
     34         for(int i = e[x]; i; i = edge[i].nex) {
     35             int y = edge[i].v;
     36             if(vis[y] == Time || !edge[i].c) {
     37                 continue;
     38             }
     39             vis[y] = Time;
     40             d[y] = d[x] + 1;
     41             Q.push(y);
     42         }
     43     }
     44     return vis[t] == Time;
     45 }
     46 
     47 int DFS(int x, int t, int maxF) {
     48     if(x == t) {
     49         return maxF;
     50     }
     51     int ans = 0;
     52     for(int i = cur[x]; i; i = edge[i].nex) {
     53         int y = edge[i].v;
     54         if(d[y] != d[x] + 1 || !edge[i].c) continue;
     55         int temp = DFS(y, t, std::min(maxF - ans, edge[i].c));
     56         if(!temp) d[y] = INF;
     57         ans += temp;
     58         edge[i].c -= temp;
     59         edge[i ^ 1].c += temp;
     60         if(ans == maxF) break;
     61         cur[x] = i;
     62     }
     63     return ans;
     64 }
     65 
     66 inline int solve(int s, int t) {
     67     int ans = 0;
     68     while(BFS(s, t)) {
     69         memcpy(cur + 1, e + 1, cnt * sizeof(int));
     70         ans += DFS(s, t, INF);
     71     }
     72     return ans;
     73 }
     74 
     75 inline int id(int i, int j) {
     76     return (i - 1) * n + j;
     77 }
     78 
     79 int main() {
     80     scanf("%d", &n);
     81     int s = n * (n + 1) + 1, t = s + 1, ans = 0, x;
     82     cnt = t;
     83     for(int i = 1; i <= n; i++) {
     84         for(int j = 1; j <= n; j++) {
     85             scanf("%d", &x);
     86             if(x > 0) {
     87                 add(s, id(i, j), x);
     88                 ans += x;
     89             }
     90             else if(x < 0) {
     91                 add(id(i, j), t, -x);
     92             }
     93             add(id(i, j), id(n + 1, i), INF);
     94             add(id(i, j), id(n + 1, j), INF);
     95         }
     96     }
     97     for(int i = 1; i <= n; i++) {
     98         scanf("%d", &x);
     99         x = -x;
    100         if(x > 0) {
    101             add(s, id(n + 1, i), x);
    102             ans += x;
    103         }
    104         else if(x < 0) {
    105             add(id(n + 1, i), t, -x);
    106         }
    107     }
    108 
    109     printf("%d", ans - solve(s, t));
    110     return 0;
    111 }
    AC代码

    BZOJ3218 a + b Problem

    题意:给你个序列,你要黑白染色。分别有贡献。每个位置还有权值。如果某个黑色位置前面有白色位置,且那个白色位置的权值在一个特定的限制中,那么要减去一个代价。求最大贡献。

    解:按照前面几题最小割的套路,我们要把每个点向它前面符合条件的白点连边。注意到这些白点是二维矩阵内的,于是主席树优化一下。

      1 #include <bits/stdc++.h>
      2 
      3 typedef long long LL;
      4 const int N = 200010;
      5 const LL INF = 0x3f3f3f3f3f3f3f3fll;
      6 
      7 struct Edge {
      8     int nex, v;
      9     LL c;
     10     Edge(int NEX = 0, int V = 0, LL C = 0) {
     11         nex = NEX;
     12         v = V;
     13         c = C;
     14     }
     15 }edge[500010]; int tp = 1;
     16 
     17 int e[N], cur[N], d[N], vis[N], Time, cnt;
     18 std::queue<int> Q;
     19 int n, a[N], lc[N], rc[N], rt[N], last[N];
     20 LL b[N], w[N], c[N];
     21 int ls[N], rs[N], X[N], xx;
     22 
     23 inline void add(int x, int y, LL z) {
     24     //if(x == n * 2 + 1 || y == n * 2 + 2) {
     25         //printf("%d %d %lld 
    ", x, y, z);
     26     //}
     27     edge[++tp] = Edge(e[x], y, z);
     28     e[x] = tp;
     29     edge[++tp] = Edge(e[y], x, 0);
     30     e[y] = tp;
     31     return;
     32 }
     33 
     34 inline bool BFS(int s, int t) {
     35     Time++;
     36     vis[s] = Time;
     37     d[s] = 0;
     38     Q.push(s);
     39     while(Q.size()) {
     40         int x = Q.front();
     41         Q.pop();
     42         for(int i = e[x]; i; i = edge[i].nex) {
     43             int y = edge[i].v;
     44             if(vis[y] == Time || !edge[i].c) {
     45                 continue;
     46             }
     47             vis[y] = Time;
     48             d[y] = d[x] + 1;
     49             Q.push(y);
     50         }
     51     }
     52     return vis[t] == Time;
     53 }
     54 
     55 LL DFS(int x, int t, LL maxF) {
     56     if(x == t) {
     57         return maxF;
     58     }
     59     LL ans = 0;
     60     for(int i = cur[x]; i; i = edge[i].nex) {
     61         int y = edge[i].v;
     62         if(d[y] != d[x] + 1 || !edge[i].c) continue;
     63         LL temp = DFS(y, t, std::min(maxF - ans, edge[i].c));
     64         if(!temp) d[y] = INF;
     65         ans += temp;
     66         edge[i].c -= temp;
     67         edge[i ^ 1].c += temp;
     68         if(ans == maxF) break;
     69         cur[x] = i;
     70     }
     71     return ans;
     72 }
     73 
     74 inline LL solve(int s, int t) {
     75     LL ans = 0;
     76     while(BFS(s, t)) {
     77         memcpy(cur + 1, e + 1, cnt * sizeof(int));
     78         ans += DFS(s, t, INF);
     79     }
     80     return ans;
     81 }
     82 
     83 void insert(int &x, int y, int p, int v, int l, int r) {
     84     if(!x || x == y) {
     85         x = ++cnt;
     86         ls[x] = ls[y];
     87         rs[x] = rs[y];
     88     }
     89     //printf("insert x = %d 
    ", x);
     90     if(l == r) {
     91         if(last[r]) {
     92             add(x, last[r], INF);
     93         }
     94         add(x, v, INF);
     95         last[r] = x;
     96         return;
     97     }
     98     int mid = (l + r) >> 1;
     99     if(p <= mid) {
    100         insert(ls[x], ls[y], p, v, l, mid);
    101     }
    102     else {
    103         insert(rs[x], rs[y], p, v, mid + 1, r);
    104     }
    105     return;
    106 }
    107 
    108 void link(int L, int R, int v, int l, int r, int o) {
    109     if(!o) return;
    110     if(L <= l && r <= R) {
    111         add(v, o, INF);
    112         return;
    113     }
    114     int mid = (l + r) >> 1;
    115     if(L <= mid) link(L, R, v, l, mid, ls[o]);
    116     if(mid < R) link(L, R, v, mid + 1, r, rs[o]);
    117     return;
    118 }
    119 
    120 void build(int l, int r, int o) {
    121     if(!o || vis[o]) return;
    122     vis[o] = 1;
    123     int mid = (l + r) >> 1;
    124     if(ls[o]) {
    125         add(o, ls[o], INF);
    126         build(l, mid, ls[o]);
    127     }
    128     if(rs[o]) {
    129         add(o, rs[o], INF);
    130         build(mid + 1, r, rs[o]);
    131     }
    132     return;
    133 }
    134 
    135 int main() {
    136 
    137     //printf("%d 
    ", (sizeof(edge) + sizeof(e) * 12 + sizeof(b) * 3) / 1048576);
    138 
    139     scanf("%d", &n);
    140     int s = n * 2 + 1, t = s + 1;
    141     cnt = t;
    142     for(int i = 1; i <= n; i++) {
    143         scanf("%d%lld%lld%d%d%lld", &a[i], &b[i], &w[i], &lc[i], &rc[i], &c[i]);
    144         X[i] = a[i];
    145     }
    146     std::sort(X + 1, X + n + 1);
    147     xx = std::unique(X + 1, X + n + 1) - X - 1;
    148     for(int i = 1; i <= n; i++) {
    149         a[i] = std::lower_bound(X + 1, X + xx + 1, a[i]) - X;
    150         lc[i] = std::lower_bound(X + 1, X + xx + 1, lc[i]) - X;
    151         rc[i] = std::upper_bound(X + 1, X + xx + 1, rc[i]) - X - 1;
    152         if(i < n) {
    153             insert(rt[i], rt[i - 1], a[i], i, 1, xx);
    154             //printf("i = %d 
    ", i);
    155         }
    156     }
    157 
    158     LL ans = 0;
    159 
    160     for(int i = 1; i <= n; i++) {
    161         add(s, i, b[i]);
    162         add(i, t, w[i]);
    163         ans += b[i] + w[i];
    164         if(lc[i] > rc[i]) {
    165             continue;
    166         }
    167         if(i > 1) {
    168             add(i, i + n, c[i]);
    169             link(lc[i], rc[i], i + n, 1, xx, rt[i - 1]);
    170         }
    171     }
    172     ++Time;
    173     for(int i = 1; i < n; i++) build(1, xx, rt[i]);
    174 
    175     printf("%lld
    ", ans - solve(s, t));
    176     return 0;
    177 }
    AC代码

    BZOJ4501 旅行

    题意:给定一张有向图,你要删去一些边,使得从1出发随机前进的期望长度最长。有些限制是删a边则必删b边,保证a和b起点相同。

    解:发现这个起点相同很妙啊,那么这些点就是互相独立的了。然后逆拓扑序考虑。对每个点来说,我们要让∑(aivi) / ∑ai最大。

    发现这是01分数规划问题,于是二分答案,就是求∑ai(vi - k)的最大值,且有些限制是不选a则一定不选b。于是先全部选了,就是选a一定选b,求最小权闭合子图即可。

      1 #include <bits/stdc++.h>
      2 
      3 typedef long long LL;
      4 const int N = 20010;
      5 const double INF = 1e9;
      6 const double eps = 1e-12;
      7 
      8 struct Edge {
      9     int nex, v;
     10     double c;
     11     Edge(int NEX = 0, int V = 0, double C = 0) {
     12         nex = NEX;
     13         v = V;
     14         c = C;
     15     }
     16 }edge[500010]; int tp = 1;
     17 
     18 struct Node {
     19     int l, r;
     20 }node[N];
     21 
     22 int e[N], cur[N], d[N], vis[N], Time, cnt;
     23 std::queue<int> Q;
     24 std::vector<int> v[N], v2[N];
     25 double val[N], Val[N];
     26 int n, m, K, e2[N], in[N], topo[N], tp2, posu[N], posv[N], in2[N], id[N];
     27 Edge edge2[N];
     28 
     29 inline void add(int x, int y, double z) {
     30     edge[++tp] = Edge(e[x], y, z);
     31     e[x] = tp;
     32     edge[++tp] = Edge(e[y], x, 0);
     33     e[y] = tp;
     34     return;
     35 }
     36 
     37 inline bool BFS(int s, int t) {
     38     Time++;
     39     vis[s] = Time;
     40     d[s] = 0;
     41     Q.push(s);
     42     while(Q.size()) {
     43         int x = Q.front();
     44         Q.pop();
     45         for(int i = e[x]; i; i = edge[i].nex) {
     46             int y = edge[i].v;
     47             if(vis[y] == Time || edge[i].c < eps) {
     48                 continue;
     49             }
     50             vis[y] = Time;
     51             d[y] = d[x] + 1;
     52             Q.push(y);
     53         }
     54     }
     55     return vis[t] == Time;
     56 }
     57 
     58 double DFS(int x, int t, double maxF) {
     59     if(x == t) {
     60         return maxF;
     61     }
     62     double ans = 0;
     63     for(int i = cur[x]; i; i = edge[i].nex) {
     64         int y = edge[i].v;
     65         if(d[y] != d[x] + 1 || edge[i].c < eps) continue;
     66         double temp = DFS(y, t, std::min(maxF - ans, edge[i].c));
     67         if(temp < eps) d[y] = INF;
     68         ans += temp;
     69         edge[i].c -= temp;
     70         edge[i ^ 1].c += temp;
     71         if(fabs(ans - maxF) < eps) break;
     72         cur[x] = i;
     73     }
     74     return ans;
     75 }
     76 
     77 inline double solve(int s, int t) {
     78     double ans = 0;
     79     while(BFS(s, t)) {
     80         memcpy(cur + 1, e + 1, cnt * sizeof(int));
     81         ans += DFS(s, t, INF);
     82     }
     83     return ans;
     84 }
     85 
     86 /// --------------------------- Dinic -------------------------------------
     87 
     88 inline void add2(int x, int y) {
     89     edge2[++tp2] = Edge(e2[x], y);
     90     e2[x] = tp2;
     91     return;
     92 }
     93 
     94 inline bool check(int x, double k) {
     95 
     96     tp = 1;
     97     memset(e + 1, 0, cnt * sizeof(int));
     98 
     99     int s = 1, t = 2;
    100     cnt = t;
    101     double ans = 0, tans = 0;
    102     for(int i = 0; i < v2[x].size(); i++) {
    103         int y = posv[v2[x][i]];
    104         Val[y] = val[y] - k;
    105         tans += Val[y];
    106         Val[y] = -Val[y];
    107         id[v2[x][i]] = ++cnt;
    108         if(Val[y] > eps) {
    109             add(s, cnt, Val[y]);
    110             ans += Val[y];
    111         }
    112         else if(Val[y] < -eps) {
    113             add(cnt, t, -Val[y]);
    114         }
    115     }
    116 
    117     for(int i = 0; i < v[x].size(); i++) {
    118         int t = v[x][i];
    119         add(id[node[t].l], id[node[t].r], INF);
    120     }
    121 
    122     ans -= solve(s, t);
    123     tans += ans;
    124     return tans > eps;
    125 }
    126 /*
    127 3 3 1
    128 1 2
    129 1 3
    130 2 3
    131 1 2
    132 
    133 */
    134 int main() {
    135 
    136     scanf("%d%d%d", &n, &m, &K);
    137     for(int i = 1, x, y; i <= m; i++) {
    138         scanf("%d%d", &x, &y);
    139         add2(x, y);
    140         v2[x].push_back(i);
    141         posu[i] = x;
    142         posv[i] = y;
    143         in[y]++;
    144         in2[x]++;
    145     }
    146     for(int i = 1, x, y; i <= K; i++) {
    147         scanf("%d%d", &node[i].r, &node[i].l);
    148         v[posu[node[i].l]].push_back(i);
    149     }
    150 
    151     for(int i = 1; i <= n; i++) {
    152         if(!in[i]) Q.push(i);
    153     }
    154     while(Q.size()) {
    155         int x = Q.front();
    156         Q.pop();
    157         topo[++cnt] = x;
    158         for(int i = e2[x]; i; i = edge2[i].nex) {
    159             int y = edge2[i].v;
    160             in[y]--;
    161             if(!in[y]) {
    162                 Q.push(y);
    163             }
    164         }
    165     }
    166 
    167     cnt = 0;
    168     for(int alpha = n; alpha >= 1; alpha--) {
    169         int x = topo[alpha];
    170         if(!in2[x]) {
    171             continue;
    172         }
    173         if(!v[x].size()) {
    174             for(int i = e2[x]; i; i = edge2[i].nex) {
    175                 int y = edge2[i].v;
    176                 val[x] = std::max(val[x], val[y]);
    177             }
    178             val[x] = val[x] + 1;
    179             continue;
    180         }
    181         double l = 0, r = m;
    182         for(int beta = 1; beta <= 40; beta++) {
    183             double mid = (l + r) / 2;
    184             if(check(x, mid)) {
    185                 l = mid;
    186             }
    187             else {
    188                 r = mid;
    189             }
    190         }
    191         val[x] = r + 1;
    192         if(x == 1) break;
    193     }
    194     printf("%.6f
    ", val[1]);
    195     return 0;
    196 }
    AC代码
  • 相关阅读:
    iOS_SN_地图的使用(3)
    iOS_SN_地图的使用(2)
    iOS_SN_百度地图基本使用(1)
    iOS_SN_CoreData(二)
    iOS_SN_CoreDate(一)封装使用
    iOS_SN_UITableView的优化
    阿里云 单表备份 恢复
    svn 彻底删除文件、文件夹
    @去除
    服务器安全保护
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10729965.html
Copyright © 2011-2022 走看看