[HNOI2013]切糕 解题报告

题目描述

经过千辛万苦小 A 得到了一块切糕,切糕的形状是长方体,小 A 打算拦腰将切糕切成两半分给小 B。出于美观考虑,小 A 希望切面能尽量光滑且和谐。于是她找到你,希望你能帮她找出最好的切割方案。 出于简便考虑,我们将切糕视作一个长 \(P\)、宽 \(Q\)、高 \(R\) 的长方体点阵。我们将位于第 \(z\) 层中第 \(x\) 行、第 \(y\) 列上的点称 \((x,y,z)\),它有一个非负的不和谐值 \(v(x,y,z)\)。一个合法的切面满足以下两个条件: - 与每个纵轴(一共有 \(P\times Q\) 个纵轴)有且仅有一个交点。即切面是一个函数 \(f(x,y)\),对于所有 \((x,y)(x\in [1,P],y\in[1,Q])\),我们需指定一个切割点 \(f(x,y)\),且 \(1\le f(x,y)\le R\)。 - 切面需要满足一定的光滑性要求,即相邻纵轴上的切割点不能相距太远。对于所有的 \(1\le x,x'\le P\)\(1\le y,y'\le Q\),若 \(|x-x'|+|y-y'|=1\),则 \(|f(x,y)-f(x',y')| \le D\),其中 \(D\) 是给定的一个非负整数。 可能有许多切面 \(f\) 满足上面的条件,小 A 希望找出总的切割点上的不和谐值最小的那个。

输入输出格式

输入格式

第一行是三个正整数 \(P,Q,R\),表示切糕的长宽高。 第二行有一个非负整数 \(D\),表示光滑性要求。 接下来是 \(R\)\(P\)\(Q\) 列的矩阵,第 \(z\) 个矩阵的第 \(x\) 行第 \(y\) 列是 \(v(x,y,z)(1\le x\le P,1\le y\le Q,1\le z\le R)\)

输出格式

仅包含一个整数,表示在合法基础上最小的总不和谐值。

SOLUTION

考虑最小割,通过连\(INF\)边强制让相邻的点不割距离超过\(D\)的边

如果没有光滑性限制

这个题就是一个ruozhi简单的最小割

在第\(r\)层的点\(x(i,j)\)与下一层 \(y\) 的连\((x,y,v[r][i][j])\)

(因为是每一\((i,j)\)选一个切割点)

这种选择的就可以考虑最小割

那有光滑限制怎么办呢

23031109014111png 699×69 fzoitop

其实就是不能切割相邻的\((x,y)\)\((x',y')\)\(r\)距离要小于等于D

那么我们就保证相邻的点的\(r\)距离大于D的不会被切割好了

\((x,y)→(x',y'),flow=INF\)

over!

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+2,INF=1e9,M=1e2+2;
struct node{ll to,val,nxt;}e[N*2];
ll a,n,vis[N],d[N],hd[N],m,ans,cnt,sum,S,T;
const ll dx[]={0,1,0,-1,0},dy[]={1,0,-1,0,0};
bool ok(ll x,ll y){return x>=1&&x<=n&&y>=1&&y<=m;}
void add(ll x,ll y,ll c){
	e[++cnt]={y,c,hd[x]};
	hd[x]=cnt;
}
bool bfs(){
	queue<ll>q;
	memset(d,0,sizeof(d));
	q.push(S);d[S]=1;
	while(!q.empty()){
		ll x=q.front();q.pop();
		for(ll i=hd[x];~i;i=e[i].nxt){
			ll y=e[i].to,w=e[i].val;
			if(w&&!d[y]){
				d[y]=d[x]+1;
				q.push(y);
				if(y==T) return 1; 
			}
		}
	}
	return 0;
}
ll dinic(ll x,ll flow){
	if(x==T) return flow;
	ll r=flow,k;
	for(ll i=hd[x];~i&&r;i=e[i].nxt){
		ll y=e[i].to,w=e[i].val;
		if(w&&d[y]==d[x]+1){
			k=dinic(y,min(r,w));
			if(!k)d[y]=0;
			e[i].val-=k;
			e[i^1].val+=k;
			r-=k;
			if(!r) return flow;
		}
	}
	return flow-r;
}
int main(){
	scanf("%lld%lld",&n,&m);
	cnt=1;
	S=0,T=3*n*m+1;
	memset(hd,-1,sizeof(hd));
	for(ll i=1;i<=n;i++){
		for(ll j=1;j<=m;j++){
			scanf("%lld",&a);
			sum+=a;
			ll x=(i-1)*m+j;
			add(S,x,a),add(x,S,0);
		}
	}
	for(ll i=1;i<=n;i++){
		for(ll j=1;j<=m;j++){
			scanf("%lld",&a);
			sum+=a;
			ll x=(i-1)*m+j;
			add(x,T,a),add(T,x,0);
		}
	}
	for(ll i=1;i<=n;i++){
		for(ll j=1;j<=m;j++){
			scanf("%lld",&a);
			sum+=a;
			ll x=(i-1)*m+j+n*m;
			add(S,x,a),add(x,S,0);
		}
	}
	for(ll i=1;i<=n;i++){
		for(ll j=1;j<=m;j++){
			scanf("%lld",&a);
			sum+=a;
			ll x=(i-1)*m+j+n*m*2;
			add(x,T,a),add(T,x,0);
		}
	}
	for(ll i=1;i<=n;i++){
		for(ll j=1;j<=m;j++){
			ll x=(i-1)*m+j;
			for(ll k=0;k<=4;k++){
				ll xi=i+dx[k],yj=j+dy[k];
				if(!ok(xi,yj))continue;
				ll y=(xi-1)*m+yj;
				add(x+n*m,y,INF),add(y,x+n*m,0);
				add(y,x+n*m*2,INF),add(x+n*m*2,y,0);
			}
		}
	}
	while(bfs()){
		ans+=dinic(S,INF);
	}
	printf("%lld",sum-ans);
	return 0;
}

完结撒花❀

★,°:.☆( ̄▽ ̄)/$:.°★

posted @ 2023-03-11 15:07  _Youngxy  阅读(38)  评论(0)    收藏  举报