最小割模板。
题意:你要在一个三维点阵的每个竖条中删去一个点,使得删去的点权和最小。
且相邻(四联通)的两竖条之间删的点的z坐标之差的绝对值不超过D。
解:
首先把这些都串起来,点边转化,就变成最小割了对吧。
那么限制条件怎么处理呢?
我们知道在最小割中流量为INF的边是割不断的,以此来连边,使得相邻的割点超过D不合法。
具体来说:把相邻的两条链中,差距刚好为D的点连起来。从上往下连INF。
这是D = 1的一个连边实例。
可以发现,我们割两个在同一高度的边是没问题的。
如果高度相差1也没问题。
如果左边的高2格,那么会被红色的边限制;如果右边的高2格又会被蓝色的边限制。
所以这样连边就能够满足限制条件了。
然后跑最小割即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }