bzoj 3144: [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

说明

最佳切面的f为f(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1

 

题解:

好题啊......这是个标准最小割模型

我们拆点,把选点改成割边

考虑如果没有限制D的话,直接对于每个位置(x,y)拆成R个点,建S->1->2->....->R连边即可 ,其实直接取min就好(-.-!)

但是如果有了对D的限制我们就要考虑对于一个位置i (i=1..R)我们如果向i-D连边便可满足D的限制,为什么?

看图:

 

如果割了红边,那么就一定不会割到绿边上.因为S还可以通过绿边上的那条inf的边到T.所以不满足割的性质

所以可以保证不割在绿边上,那么同理从右边的i也要连向i左边的i-D  (此图中没画出)

 

由此可以总结出最小割题目的套路:

如果一条边不能被割,我们就向它所到的点连一条inf的边 这样就依然存在到T的增广路...

 

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #define id(a,b,c) (((a)-1)*41*41+((b)-1)*41+(c))
 8 using namespace std;
 9 const int MS=45,N=100005,M=550000,inf=2e8;
10 int n,m,R,map[MS][MS][MS];
11 int nxt[M],num=1,to[M],dis[M],head[N],D,S=0,T;
12 void init(int x,int y,int dist){
13     nxt[++num]=head[x];to[num]=y;dis[num]=dist;head[x]=num;
14 }
15 void addedge(int x,int y,int dist){
16     init(x,y,dist);init(y,x,0);
17 }
18 int q[N],dep[N];
19 bool bfs(){
20     int t=0,sum=1,x,u;
21     memset(dep,0,sizeof(dep));
22     dep[S]=1;q[1]=S;
23     while(t!=sum){
24         x=q[++t];
25         for(int i=head[x];i;i=nxt[i]){
26             u=to[i];
27             if(dep[u] || dis[i]<=0)continue;
28             dep[u]=dep[x]+1;q[++sum]=u;
29         }
30     }
31     return dep[T];
32 }
33 int dfs(int x,int flow){
34     if(x==T || !flow)return flow;
35     int u,tmp,tot=0;
36     for(int i=head[x];i;i=nxt[i]){
37         u=to[i];
38         if(dep[u]!=dep[x]+1 || dis[i]<=0)continue;
39         tmp=dfs(u,min(flow,dis[i]));
40         dis[i]-=tmp;dis[i^1]+=tmp;
41         tot+=tmp;flow-=tmp;
42         if(!flow)break;
43     }
44     if(!tot)dep[x]=0;
45     return tot;
46 }
47 int maxflow(){
48     int tot=0,tmp;
49     while(bfs()){
50         tmp=dfs(S,inf);
51         while(tmp)tot+=tmp,tmp=dfs(S,inf);
52     }
53     return tot;
54 }
55 void work()
56 {
57     scanf("%d%d%d%d",&n,&m,&R,&D);
58     T=N-1;
59     for(int i=1;i<=R;i++){
60         for(int j=1;j<=n;j++)
61             for(int k=1;k<=m;k++){
62                 scanf("%d",&map[j][k][i]);
63                 addedge(id(j,k,i),id(j,k,i+1),map[j][k][i]);
64             }
65     }
66     for(int j=1;j<=n;j++)
67         for(int k=1;k<=m;k++){
68             addedge(S,id(j,k,1),inf);
69             for(int i=D+1;i<=R;i++){
70                 if(j>1)addedge(id(j,k,i),id(j-1,k,i-D),inf);
71                 if(k>1)addedge(id(j,k,i),id(j,k-1,i-D),inf);
72                 if(j<n)addedge(id(j,k,i),id(j+1,k,i-D),inf);
73                 if(k<m)addedge(id(j,k,i),id(j,k+1,i-D),inf);
74             }
75             addedge(id(j,k,R+1),T,inf);
76         }
77     printf("%d\n",maxflow());
78 }
79  
80 int main()
81 {
82     work();
83     return 0;
84 }
85 

 

posted @ 2017-08-15 19:53  PIPIBoss  阅读(279)  评论(0编辑  收藏  举报