[HNOI2013] 切糕

  有一个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++

相关文章
相关标签/搜索