[BZOJ 3144]切糕

这里引用一下别人的题解

最小割模型,非常好的题目

3144: [Hnoi2013]切糕



Input
第一行是三个正整数P,Q,R,表示切糕的长P、 宽Q、高R。第二行有一个非负整数D,表示光滑性要求。接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤P, 1≤y≤Q, 1≤z≤R)。 
100%的数据满足P,Q,R≤40,0≤D≤R,且给出的所有的不和谐值不超过1000。
Output
仅包含一个整数,表示在合法基础上最小的总不和谐值。
Sample Input
2  2 2 

6  1
6  1
2  6
2  6
Sample Output
6
HINT
最佳切面的f为f(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1



http://blog.csdn.net/zarxdy34/article/details/45272055





#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

#define maxn 50
#define Node(k, i, j) ((k - 1) * P * Q + (i - 1) * Q + j)
using namespace std;

int P, Q, R, D;

int a[maxn][maxn][maxn];

int S, T;

struct Edge{
	int to, next, w;
}edge[2000010];

int cnt = 1, h[100010];

void add(int u, int v, int w){
	cnt ++;
	edge[cnt].to = v;
	edge[cnt].next = h[u];
	edge[cnt].w = w;
	h[u] = cnt;
	swap(u, v);w = 0;
	cnt ++;
	edge[cnt].to = v;
	edge[cnt].next = h[u];
	edge[cnt].w = w;
	h[u] = cnt;
}

const int dx[] = {0, 0, -1, 1};
const int dy[] = {1, -1, 0, 0};
const int inf = 0x7fffffff;

bool isinit(int x, int y){
	return x > 0 && y > 0 && x <= P && y <= Q;
}

queue<int>q;

int d[100010];

bool BFS(){
	q.push(S);
	memset(d, -1, sizeof d);
	d[S] = 0;
	while(!q.empty()){
		int u = q.front();q.pop();
		for(int i = h[u]; i; i = edge[i].next){
			if(!edge[i].w)continue;
			int v = edge[i].to;
			if(d[v] == -1){
				d[v] = d[u] + 1;
				q.push(v);
			}
		}
	}return d[T] != -1;
}

int DFS(int x, int a){
	if(a == 0 || x == T)return a;
	int used = 0, f;
	for(int i = h[x]; i; i = edge[i].next){
		int v = edge[i].to;
		if(d[v] == d[x] + 1){
			f = DFS(v, min(edge[i].w, a - used));
			edge[i].w -= f;
			edge[i ^ 1].w += f;
			used += f;
			if(used == a)return used;
		}
	}
	if(!used)d[x] = -1;
	return used;
}

void Dinic(){
	int ret = 0;
	while(BFS())
		ret += DFS(S, inf);
	printf("%d\n", ret);
}

int main(){
	scanf("%d%d%d%d", &P, &Q, &R, &D);
	for(int i = 1; i <= R; i ++)
		for(int j = 1; j <= P; j ++)
			for(int k = 1; k <= Q; k ++)
				scanf("%d", &a[i][j][k]);
	S = 0, T = P * Q * R + 1;
	int n = P, m = Q;

	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= m; j ++){
			add(S, Node(1, i, j), a[1][i][j]);
			add(Node(R, i, j), T, inf);
			for(int k = 2; k <= R; k ++){
                add(Node(k - 1, i, j), Node(k, i, j), a[k][i][j]);
                if(k <= D)continue;
                for(int p = 0; p < 4; p ++){
	                int u = i + dx[p], v = j + dy[p];
					if(!isinit(u, v))continue;
					add(Node(k, i, j), Node(k - D, u, v), inf);
                }
			}
		}
	}
	
	Dinic();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值