【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;
}
posted @ 2019-02-18 15:40  xgzc  阅读(140)  评论(0编辑  收藏  举报