洛谷P3227 切糕

最小割模板。

题意:你要在一个三维点阵的每个竖条中删去一个点,使得删去的点权和最小。

且相邻(四联通)的两竖条之间删的点的z坐标之差的绝对值不超过D。

解:

首先把这些都串起来,点边转化,就变成最小割了对吧。

那么限制条件怎么处理呢?

我们知道在最小割中流量为INF的边是割不断的,以此来连边,使得相邻的割点超过D不合法。

具体来说:把相邻的两条链中,差距刚好为D的点连起来。从上往下连INF。

这是D = 1的一个连边实例。

可以发现,我们割两个在同一高度的边是没问题的。

如果高度相差1也没问题。

如果左边的高2格,那么会被红色的边限制;如果右边的高2格又会被蓝色的边限制。

所以这样连边就能够满足限制条件了。

然后跑最小割即可。

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

 

posted @ 2018-12-07 21:40  huyufeifei  阅读(166)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

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