[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)\)选一个切割点)
这种选择的就可以考虑最小割
那有光滑限制怎么办呢
其实就是不能切割相邻的\((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;
}
完结撒花❀
★,°:.☆( ̄▽ ̄)/$:.°★ 。


浙公网安备 33010602011771号