BZOJ 3144 HNOI 2013 切糕 最小割

题目大意:给出一个三维的点阵,没个点都有可能被切割,代价就是这个点的权值。相邻的切割点的高度差不能超过D,问最小的花费使得上下分开。

思路:很裸的最小割模型,很神的建图。

S->第一层的点,f:INF

所有点->它下面的点,f:INF

一个点的入->一个点的出,f:val[i]

(i,j,k) - > (i - d,j,k),f:INF

最下面一层的点->T:f:INF

然后跑最小割就是答案。

为什么见:http://www.cnblogs.com/zyfzyf/p/4182168.html OTZ ZYF

CODE:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 130000
#define MAXE 1200000
#define S 0
#define T (MAX - 1)
#define INF 0x3f3f3f3f
using namespace std;
const int dx[] = {0,1,-1,0,0};
const int dy[] = {0,0,0,1,-1};

struct MaxFlow{
	int head[MAX],total;
	int next[MAXE],aim[MAXE],flow[MAXE];
	int deep[MAX];

	MaxFlow() {
		total = 1;
		memset(head,0,sizeof(head));
	}
	void Add(int x,int y,int f) {
		next[++total] = head[x];
		aim[total] = y;
		flow[total] = f;
		head[x] = total;
	}
	void Insert(int x,int y,int f) {
		Add(x,y,f);
		Add(y,x,0);
	}
	bool BFS() {
		static queue<int> q;
		while(!q.empty())	q.pop();
		memset(deep,0,sizeof(deep));
		deep[S] = 1;
		q.push(S);
		while(!q.empty()) {
			int x = q.front(); q.pop();
			for(int i = head[x]; i; i = next[i])
				if(flow[i] && !deep[aim[i]]) {
					deep[aim[i]] = deep[x] + 1;
					q.push(aim[i]);
					if(aim[i] == T)	return true;
				}
		}
		return false;
	}
	int Dinic(int x,int f) {
		if(x == T)	return f;
		int temp = f;
		for(int i = head[x]; i; i = next[i])
			if(flow[i] && temp && deep[aim[i]] == deep[x] + 1) {
				int away = Dinic(aim[i],min(flow[i],temp));
				if(!away)	deep[aim[i]] = 0;
				flow[i] -= away;
				flow[i^1] += away;
				temp -= away;
			}
		return f - temp;
	}
}solver;

int P,Q,R,D;
int src[50][50][50],num[50][50][50],cnt;

int main()
{
	cin >> 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",&src[i][j][k]),num[i][j][k] = ++cnt;
				solver.Insert(num[i][j][k] << 1,num[i][j][k] << 1|1,src[i][j][k]);
			}
	for(int i = 1; i <= P; ++i)
		for(int j = 1; j <= Q; ++j) {
			solver.Insert(S,num[1][i][j] << 1,INF);
			solver.Insert(num[R][i][j] << 1|1,T,INF);
		}
	for(int i = 1; i <= R; ++i)
		for(int j = 1; j <= P; ++j)
			for(int k = 1; k <= Q; ++k) {
				if(i != R)
					solver.Insert(num[i][j][k] << 1|1,num[i + 1][j][k] << 1,INF);
				for(int d = 1; d <= 4; ++d) {
					int fx = j + dx[d],fy = k + dy[d];
					if(!fx || !fy || fx > P || fy > Q)	continue;
					if(i - D > 0)	solver.Insert(num[i][j][k] << 1,num[i - D][fx][fy] << 1,INF);
				}
			}
	int max_flow = 0;
	while(solver.BFS())
		max_flow += solver.Dinic(S,INF);
	cout << max_flow << endl;
	return 0;
}

时间: 2024-10-24 09:45:32

BZOJ 3144 HNOI 2013 切糕 最小割的相关文章

BZOJ 2007 海拔(平面图最小割-最短路)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2007 题意:给出一个n*n的格子,那么顶点显然有(n+1)*(n+1)个.每两个相邻顶点之间有两条边,这两条边是有向的,边上有权值..左上角为源点,右下角为汇点,求s到t的最小割. 思路:很明显这是一个平面图,将其转化为最 短路.我们将s到t之间连一条边,左下角为新图的源点S,右上角区域为新图的终点T,并且为每个格子编号.由于边是有向的,我们就要分析下这条边应该是哪 个点向哪个点的边.

bzoj 3144: [Hnoi2013]切糕 最小割

3144: [Hnoi2013]切糕 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 681  Solved: 375[Submit][Status] Description 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≤

【BZOJ-3144】切糕 最小割-最大流

3144: [Hnoi2013]切糕 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1261  Solved: 700[Submit][Status][Discuss] Description 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

[BZOJ 3894] 文理分科 【最小割】

题目链接:BZOJ - 3894 题目分析 最小割模型,设定一个点与 S 相连表示选文,与 T 相连表示选理. 那么首先要加上所有可能获得的权值,然后减去最小割,即不能获得的权值. 那么对于每个点,从 S 向它连权值为它选文的价值的边,从它向 T 连权值为它选理的价值的边. 对于一个点,它和与它相邻的点构成了一个集合,这个集合如果都选文,可以获得一个价值v1,如果都选理,可以获得一个价值 v2. 只要这个集合中有一个点选文,就无法获得 v2,只要有一个点选理,就无法获得 v1. 那么处理方式就是

BZOJ 3774: 最优选择( 最小割 )

最小割...二分染色然后把颜色不同的点的源汇反过来..然后就可以做了. 某个点(x,y): S->Id(x,y)(回报), Id(x,y)->T(代价), Id(i,j)&&Id(相邻节点)->newId(i,j)(+oo), newId(i,j)->T(回报) 然后染色不同的点反过来就可以了. 初始时答案为2*∑回报, 这样每个点要么割掉1个回报,要么割掉2个回报, 要么割掉1回报+代价.都对应着每一种方案 ----------------------------

BZOJ 3275 Number &amp;&amp; 3158 千钧一发 最小割

题目大意:给出一些数字,要求选出一些数字并保证所有数字和最大,要求这其中的数字任意两个至少满足一个条件,则不能同时被选:1.这两个数的平方和是完全平方数.2.gcd(a,b) = 1. 思路:我们可以将奇数和偶数分开来讨论,奇数不满足1,偶数不满足2,所以奇数和奇数,偶数和偶数不会互相影响.之后O(n^2)的讨论其他数字对,有影响就连边,流量正无穷,最后跑最小割最最大获利. CODE: #define _CRT_SECURE_NO_WARNINGS #include <cmath> #incl

cogs2398 切糕 最小割

链接:http://cogs.pro/cogs/problem/problem.php?pid=2398 题意:找到一个最小割使损失最小. 字面意思,单纯的最小割.对于每一个点$(i,j,k)$,我们将其与它下方的点$(i,j,k-1)$,连一条容量为该点不和谐度的边,如果高度为1,连到源点,高度为n,建出一条到汇点容量无限大的边.对于高度超过限制高度的点,我们由周围下方可行点向它连容量无限大边. 1 #include<iostream> 2 #include<cstdio> 3

BZOJ 1934 善意的投票(最小割)

把人分成两个集合,一个赞成睡觉,一个反对睡觉.好朋友连一条容量为1的双向边,s向赞成睡觉的连边,反对睡觉的向t连边. 那么这个图的一个割就对应着一个方案.如果割掉s和v的边,就代表v投意见与它自己相反的票,t和v的边同理.割掉u和v的边,就代表了这对好朋友之间意见不同. 这样求出一个割之后,好朋友之间意见不同的边都被割去了. 求出此图的最小割即为答案. # include <cstdio> # include <cstring> # include <cstdlib>

BZOJ 2007 NOI2010 海拔 平面图最小割

题目大意:YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作一个正方形,每一个区域也可看作一个正方形.从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路(简称道路),每条双向道路连接主干道上两个相邻的交叉路口.下图为一张YT市的地图(n = 2),城市被划分为2×2个区域,包括3×3个交叉路口和12条双向道路. 小Z作为该市的市长,他根据统计信息得到了每天上班高峰期间YT市每条道路两个方向的人流量,即在高峰期间沿着