[HNOI2013]切糕

题目描述

经过千辛万苦小 A 得到了一块切糕,切糕的形状是长方体,小 A 打算拦腰将切糕切成两半分给小 B。出于美观考虑,小 A 希望切面能尽量光滑且和谐。于是她找到你,希望你能帮她找出最好的切割方案。

出于简便考虑,我们将切糕视作一个长 P、宽 Q、高 R 的长方体点阵。我们将位于第 z层中第 x 行、第 y 列上(1≤x≤P, 1≤y≤Q, 1≤z≤R)的点称为(x,y,z),它有一个非负的不和谐值 v(x,y,z)。一个合法的切面满足以下两个条件:

  1. 与每个纵轴(一共有 P*Q 个纵轴)有且仅有一个交点。即切面是一个函数 f(x,y),对于所有 1≤x≤P, 1≤y≤Q,我们需指定一个切割点 f(x,y),且 1≤f(x,y)≤R。

  2. 切面需要满足一定的光滑性要求,即相邻纵轴上的切割点不能相距太远。对于所有的 1≤x,x’≤P 和 1≤y,y’≤Q,若|x-x’|+|y-y’|=1,则|f(x,y)-f(x’,y’)| ≤D,其中 D 是给定的一个非负整数。 可能有许多切面f 满足上面的条件,小A 希望找出总的切割点上的不和谐值最小的那个。

输入输出格式

输入格式:

第一行是三个正整数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<=R,且给出的所有的不和谐值不超过1000。

输出格式:

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

输入输出样例

输入样例#1:
2  2 2
1
6  1
6  1
2  6
2  6
输出样例#1:
6

将模型简化一下,变成对于两个相邻点(x1,y1)和(x2,y2)的最小和谐值,如图
由于答案是最小,所以考虑最小割
因为一个点只选一层和谐值,所以考虑每相邻楼层建边,每个(x,y)形成一个长为r的路径
此处为方便处理,先再度入时给节点标号,为nu[i][j][k](num重名)
E=(nu[i][j][k],nu[i][j][k+1],w[i][j][k])
接下来考虑怎么使相邻高度差不大于d
如图所示,因为条件是相邻,所以只要与四个方向点(x',y')对应的路径建边
如何建边?要使选择了(x,y)对应路径的第k号路的相邻路径只能选第[k-d,k+d]条
只要加边(nu[i][j][k],nu[x][y][k-d],inf) 这条边不能被割
如果割边选的是第[1,k-d-1]或[k+d+1,r]流都会通过新加边到达T,与割定义不符
所以在这样的模型下跑一边最大流就行了

给出一种减少超时的方法(见下红代码)
解释:
事先复制head数组(链式前向星)为cur,之后重点在“&”号上面,它会使cur随i的变化而变化
也就是说,这条边遍历了,求出了流,下一次就会跳过遍历过的边
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 struct Node
  8 {
  9     int next,to,dis;
 10 }edge[2000001];
 11 int num,head[1000001],n,m,d,r,nu[51][51][51],dist[1000001],cnt,ans,cur[1000001];
 12 const int dx[5]={0,1,-1,0,0};
 13 const int dy[5]={0,0,0,1,-1};
 14 void add(int u,int v,int dis)
 15 {
 16     //cout<<u<<' '<<v<<' '<<dis<<endl;
 17     edge[num].next=head[u];
 18     edge[num].to=v;
 19     edge[num].dis=dis;
 20     head[u]=num++;
 21     
 22     edge[num].next=head[v];
 23     edge[num].to=u;
 24     edge[num].dis=0;
 25     head[v]=num++;
 26 }
 27 bool bfs(int S,int T)
 28 {
 29     int i;
 30     memset(dist,-1,sizeof(dist));
 31     queue<int>Q;
 32     Q.push(S);
 33     dist[S]=1;
 34     while (!Q.empty())
 35     {
 36         int u=Q.front();
 37         Q.pop();
 38          for (i=head[u];i!=-1;i=edge[i].next)
 39          {
 40             int v=edge[i].to;
 41              if (edge[i].dis>0&&dist[v]==-1)
 42              {
 43                 dist[v]=dist[u]+1;
 44                 Q.push(v);
 45              }
 46          }
 47     }
 48      if (dist[T]==-1) return 0;
 49        return 1;
 50 }
 51 int dfs(int x,int flow,int des)
 52 {
 53     int res=0;
 54     //cout<<x<<endl;
 55      if (flow<=0||x==des) return flow;
 56      for (int &i=cur[x];i!=-1;i=edge[i].next)
 57      {
 58          if (dist[edge[i].to]==dist[x]+1&&edge[i].dis>0)
 59          {
 60              int tmp=dfs(edge[i].to,min(flow-res,edge[i].dis),des);
 61              if (tmp<=0) continue;
 62              edge[i^1].dis+=tmp;
 63              edge[i].dis-=tmp;
 64               res+=tmp;
 65               if (res==flow) return res;
 66          }
 67      }
 68 return res;
 69 }
 70 int main()
 71 {int k,i,j,p,v;
 72     cin>>n>>m>>r;
 73     cnt=0;
 74     cin>>d;
 75     memset(head,-1,sizeof(head));
 76   for (k=1;k<=r+1;k++)
 77   {
 78     for (i=1;i<=n;i++)
 79     {
 80       for (j=1;j<=m;j++)
 81        {
 82          nu[i][j][k]=++cnt;
 83        }  
 84     }
 85   }
 86   
 87    for (i=1;i<=n;i++)
 88    {
 89     for (j=1;j<=m;j++)
 90      add(0,nu[i][j][1],2e9),add(nu[i][j][r+1],cnt+1,2e9);
 91    }
 92     
 93 for (k=1;k<=r;k++)
 94   {
 95     for (i=1;i<=n;i++)
 96     {
 97       for (j=1;j<=m;j++)
 98        {
 99         scanf("%d",&v);
100          add(nu[i][j][k],nu[i][j][k+1],v);
101        }  
102     }
103   }
104   for (i=d+1;i<=r;i++)
105    {
106     for (j=1;j<=n;j++)
107      {
108         for (k=1;k<=m;k++)
109         {
110             for (p=1;p<=4;p++)
111             {
112                 int x=j+dx[p],y=k+dy[p];
113                 if (x&&y&&x<=n&&y<=m)
114                 {
115                   add(nu[j][k][i],nu[x][y][i-d],2e9);
116                 }
117             }
118         }
119      }
120    }
121     while (bfs(0,cnt+1))
122     {
123         int a=0;
124         memcpy(cur,head,sizeof(cur));
125         while (a=dfs(0,2e9,cnt+1)) ans+=a;
126     }
127     cout<<ans;
128 }

 

posted @ 2017-08-18 21:57  Z-Y-Y-S  阅读(310)  评论(0编辑  收藏  举报