题目大意:有一个$n imes m$的切糕,每一个位置的高度可以在$[1,k]$之间,每个高度有一个代价,要求四联通的两个格子之间高度最多相差$D$,问可行的最小代价。$n,m,k,Dleqslant 40$
题解:网络流,不考虑相差为$D$的条件时,可以给每个位置建一个点,源点连向高度为$1$的点容量为$infty$,高度为$i$的点连向这个位置高度为$i+1$的点,容量为代价,高度为$k$的连向汇点,容量为代价。跑最小割。
考虑相差为$D$的条件,可以对于相邻的两个点$A,B$,连接$A_i o B_{i-D}$的容量为$infty$的边这样就强制限定两个点的最小割必须相距小于等于$D$,跑最小割即可
卡点:加边的时候多加了$k$倍,导致又$TLE$又$RE$
C++ Code:
#include <cstdio> #include <cctype> #include <algorithm> const int inf = 0x3f3f3f3f; namespace std { struct istream { #define M (1 << 24 | 3) char buf[M], *ch = buf - 1; inline istream() { fread(buf, 1, M, stdin); } inline istream& operator >> (int &x) { while (isspace(*++ch)); for (x = *ch & 15; isdigit(*++ch); ) x = x * 10 + (*ch & 15); return *this; } #undef M } cin; struct ostream { #define M (1 << 10 | 3) char buf[M], *ch = buf - 1; inline ostream& operator << (int x) { if (!x) {*++ch = '0'; return *this;} static int S[20], *top; top = S; while (x) {*++top = x % 10 ^ 48; x /= 10;} for (; top != S; --top) *++ch = *top; return *this; } inline ostream& operator << (const char x) {*++ch = x; return *this;} inline ~ostream() { fwrite(buf, 1, ch - buf + 1, stdout); } #undef M } cout; } namespace Network_Flow { const int maxn = 50 * 50 * 50, maxm = maxn * 6; int lst[maxn], head[maxn], cnt = 1; struct Edge { int to, nxt, w; } e[maxm << 1]; void addedge(int a, int b, int c) { e[++cnt] = (Edge) { b, head[a], c }; head[a] = cnt; e[++cnt] = (Edge) { a, head[b], 0 }; head[b] = cnt; } int st, ed, n, MF; int GAP[maxn], dis[maxn], q[maxn], h, t; void init() { GAP[dis[q[h = t = 0] = ed] = 1] = 1; for (int i = st; i <= ed; ++i) lst[i] = head[i]; while (h <= t) { int u = q[h++]; for (int i = head[u], v; i; i = e[i].nxt) { v = e[i].to; if (!dis[v]) { ++GAP[dis[v] = dis[u] + 1]; q[++t] = v; } } } } int dfs(int u, int low) { if (!low || u == ed) return low; int w, res = 0; for (int &i = lst[u], v; i; i = e[i].nxt) if (e[i].w) { v = e[i].to; if (dis[u] == dis[v] + 1) { w = dfs(v, std::min(low, e[i].w)); res += w, low -= w; e[i].w -= w, e[i ^ 1].w += w; if (!low) return res; } } if (!--GAP[dis[u]]) dis[st] = n + 1; ++GAP[++dis[u]], lst[u] = head[u]; return res; } void ISAP(int S, int T) { st = S, ed = T, n = T - S + 1; init(); while (dis[st] <= n) MF += dfs(st, inf); } } int n, m, h, D; int v[50][50][50]; int pos[50][50][50], idx, st, ed; void addedge(int x, int y, int z, int w) { for (int i = D + 1; i <= h; ++i) Network_Flow::addedge(pos[x][y][i], pos[z][w][i - D], inf); } int main() { std::cin >> n >> m >> h >> D; for (int i = 1; i <= h; ++i) for (int j = 1; j <= n; ++j) for (int k = 1; k <= m; ++k) { pos[j][k][i] = ++idx; std::cin >> v[j][k][i]; } st = 0, ed = ++idx; for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) { for (int k = 1; k <= h; ++k) { if (k == 1) Network_Flow::addedge(st, pos[i][j][k], inf); if (k == h) Network_Flow::addedge(pos[i][j][k], ed, v[i][j][k]); else Network_Flow::addedge(pos[i][j][k], pos[i][j][k + 1], v[i][j][k]); } if (i != 1) addedge(i, j, i - 1, j); if (i != n) addedge(i, j, i + 1, j); if (j != 1) addedge(i, j, i, j - 1); if (j != n) addedge(i, j, i, j + 1); } Network_Flow::ISAP(st, ed); std::cout << Network_Flow::MF << ' '; return 0; }