有一個n*m*h的切糕,你須要給全部n*m條縱軸肯定一個切點(x,y,z),表示切掉座標爲(x,y,z)的點。規定相鄰的縱軸不能相距太遠,具體若兩條縱軸(x1,y1),(x2,y2) 四聯通,那麼要求知足 |z1-z2|<=D。其中D是給定的常數。每一個點有不和諧度,請求出切出的點的最小不和諧度。 n,m,h<=40。
Solution
第一眼有最大權閉合子圖的感受,可是又不是很同樣。最大權閉合子圖是規定了若是選擇了一個點那麼它連出去的全部點都要選擇,可是這裏只用選擇連出去的全部出邊中的一個點便可。
這種規定某些點只能取其一的模型,放在最大流裏就是新建一個節點,源點向這個節點連容量爲1的邊,而後再從這個節點向其它節點連容量爲1的邊,可是這樣就處理不了點權的問題了,因此咱們考慮最小割。那這種模型放在最小割裏就是把這些節點連成一串,把點權反映到邊權上,若是割掉了某條邊就表明選/不選這個點,由於求出的是最小割,那這一串邊只會選擇某一條割掉,也就是說只會選擇一個點。
再加上D的限制就作完了。其實有D也很簡單,就是規定了若是割掉某條邊以後必定要在這條邊對應的點的連出去的出邊中選擇一條割掉。假設割掉了(x,y,z),那對於(x-1,y)這條縱軸,咱們割掉的z'必定知足z-D<=z'<=z+D,那麼能夠從(x,y,z)向(x-1,y,z-D)連一條容量爲inf的邊,從(x-1,y,z+D+1)向(x,y,z+1)連一條容量爲inf的邊,表示若是不割掉z-D<=z'<=z+D中的點的話那這就不是一個合法的割了,這樣就保證了答案的正確性。
Code
#include<bits/stdc++.h>
using std::min;
using std::max;
using std::swap;
using std::vector;
typedef double db;
typedef long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define all(A) A.begin(),A.end()
#define mp(A,B) std::make_pair(A,B)
const int N=1e5+5;
const int inf=1e9;
int n,m,h,D,s,t,cnt=1;
int head[N],d[N],val[41][41][41];
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
struct Edge{
int to,nxt,flow;
}edge[5120000];
void add(int x,int y,int z){
edge[++cnt].to=y;edge[cnt].nxt=head[x];edge[cnt].flow=z;head[x]=cnt;
edge[++cnt].to=x;edge[cnt].nxt=head[y];edge[cnt].flow=0;head[y]=cnt;
}
bool bfs(){
std::queue<int> q;q.push(s);
memset(d,0,sizeof d);d[s]=1;
while(q.size()){
int u=q.front();q.pop();
for(int i=head[u];i;i=edge[i].nxt){
int to=edge[i].to;
if(!d[to] and edge[i].flow){
d[to]=d[u]+1;q.push(to);
if(to==t) return 1;
}
}
} return 0;
}
int dinic(int now,int flow){
if(now==t) return flow;
int res=flow;
for(int i=head[now]www.tiaotiaoylzc.com/;i;i=edge[i].nxt){
int to=edge[i].to;
if(d[to]==d[now]+1 www.huayi1.cn and edge[i].flow){
int k=dinic(to,min(res,edge[i].flow));
if(!k) d[to]=0;
edge[i].flow-=k,edge[i^1].flow+=k,res-=k;
if(!res) return flow;
}
} return flow-res;
}
int getint(){
int X=0,w=0;char ch=getchar();
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=www.tongqt178.com X*10+ch-48,ch=getchar();
if(w) return -X;return X;
}
int num(int x,int y,int z){
return n*m*(z-1)+(x-1)*m+y;
}
int idx(int x,int y){
return n*m*h+(x-1)*m+y;
}
signed main(){
n=getint(),m=getint(www.ysyl157.com ),h=getint(),D=getint();
t=n*m*h+n*m+5;
for(int z=1;z<=h;z++)
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
val[i][j][z]=getint();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
add(s,num(i,j,1),inf);
for(int z=1;z<h;z++)
add(num(i,j,z),num(i,j,z+1),val[i][j][z]);
add(num(i,j,h),idx(i,j),val[i][j][h]);
add(idx(i,j),t,inf);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j+yongshiyule178.com+){
for(int k=0;k<4;k++){
int nx=i+dx[k],ny=j+dy[k];
if(nx>=1 and nx<=n and ny>www.mcyllpt.com =1 and ny<=m){
for(int z=1;z<=h;z++){
add(num(i,j,z),num(nx,ny,min(z-D,1)),inf);
if(z+D+1<=h) {c++