【HNOI2013】切糕
题面
题解
新建第\(R + 1\)层,将切点换成割边,然后就出现了最小割模型
然后从源点\(S\)向第一层的每个点连一条容量为\(\infty\)的边,从第\(R + 1\)层的每个点向汇点\(T\)连一条容量为\(\infty\)的边,这些边不会被割掉。
首先不考虑\(D\)的限制,从\((i, j, k) \to (i, j, k + 1)\)连一条容量为\(val[i][j][k]\)的边。
然后考虑\(D\)的限制,假设\((i, j)\)与\((k, l)\)是相邻的,那么我们要让\(f(i, j) - f(k, l) > D\)时也能有从\(S \to T\)的流,
那么从\((i, j, z)\)向\((k, l, z - D)\)连一条容量为\(\infty\)的边就可以了
代码
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define RG register
#define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
inline int read()
{
int data = 0, w = 1; char ch = getchar();
while(ch != '-' && (!isdigit(ch))) ch = getchar();
if(ch == '-') w = -1, ch = getchar();
while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
return data * w;
}
const int maxn(250010), maxm(1000000), N(45), INF(0x3f3f3f3f);
const int dx[] = {0, 1, 0, -1};
const int dy[] = {1, 0, -1, 0};
int P, Q, R, D, idcnt;
int val[N][N][N];
int id[N][N][N];
struct edge { int next, to, cap; } e[maxm];
int head[maxn], e_num = -1, S, T;
inline void add_edge(int from, int to, int cap)
{
e[++e_num] = (edge) {head[from], to, cap}; head[from] = e_num;
e[++e_num] = (edge) {head[to], from, 0 }; head[to] = e_num;
}
int q[maxn], tail, lev[maxn], cur[maxn];
int bfs()
{
memset(lev, 0, sizeof lev); q[tail = lev[S] = 1] = S;
for(RG int i = 1; i <= tail; i++)
{
int x = q[i];
for(RG int j = head[x]; ~j; j = e[j].next)
{
int to = e[j].to;
if(lev[to] || (!e[j].cap)) continue;
q[++tail] = to, lev[to] = lev[x] + 1;
}
}
return lev[T];
}
int dfs(int x, int f)
{
if(x == T || (!f)) return f;
int ans = 0, cap;
for(RG int &i = cur[x]; ~i; i = e[i].next)
{
int to = e[i].to;
if(e[i].cap && lev[to] == lev[x] + 1)
{
cap = dfs(to, std::min(f - ans, e[i].cap));
e[i].cap -= cap, e[i ^ 1].cap += cap, ans += cap;
if(ans == f) break;
}
}
if(!ans) lev[x] = 0;
return ans;
}
inline int Dinic()
{
int ans = 0;
while(bfs())
{
for(RG int i = S; i <= T; i++) cur[i] = head[i];
ans += dfs(S, INF);
}
return ans;
}
int main()
{
memset(head, -1, sizeof head); S = ++idcnt;
P = read(), Q = read(), R = read(), D = read();
for(RG int k = 1; k <= R; k++)
for(RG int i = 1; i <= P; i++)
for(RG int j = 1; j <= Q; j++)
val[i][j][k] = read();
for(RG int i = 1; i <= P; i++)
for(RG int j = 1; j <= Q; j++)
for(RG int k = 1; k <= R + 1; k++)
id[i][j][k] = ++idcnt;
T = ++idcnt;
for(RG int i = 1; i <= P; i++)
for(RG int j = 1; j <= Q; j++)
add_edge(S, id[i][j][1], INF),
add_edge(id[i][j][R + 1], T, INF);
for(RG int i = 1; i <= P; i++)
for(RG int j = 1; j <= Q; j++)
for(RG int k = 1; k <= R; k++)
add_edge(id[i][j][k], id[i][j][k + 1], val[i][j][k]);
for(RG int i = 1; i <= P; i++)
for(RG int j = 1; j <= Q; j++)
for(int d = 0; d < 4; d++)
{
int tx = dx[d] + i, ty = dy[d] + j;
if(tx < 1 || tx > P || ty < 1 || ty > Q) continue;
for(RG int k = D + 1; k <= R + 1; k++)
add_edge(id[i][j][k], id[tx][ty][k - D], INF);
}
printf("%d\n", Dinic());
return 0;
}