【BZOJ 3144】 3144: [Hnoi2013]切糕 (最小割模型)
3144: [Hnoi2013]切糕
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1764 Solved: 965Description
Input
第一行是三个正整数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。Output
仅包含一个整数,表示在合法基础上最小的总不和谐值。
Sample Input
2 2 2
1
6 1
6 1
2 6
2 6
Sample Output
6HINT
最佳切面的f为f(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1
Source
【题意】
三维的图,每个x,y选一个高度,每个高度有一个值v[x][y][h],相邻的(x,y)选的h的差要小于等于D,使得总的v最小,问最小值。
【分析】
我不知道的最小割经典模型?
这个题是个挺经典的最小割。
这个题的关键是如何限制h之差不超过d。首先我们按高度分层,每层的点向下一层相同位置的点连边,边权设为点权(也就是说我们要多设一层),然后如果我们割掉这条边就意味着选择了下面这个点。然后,对于h之差的限制,我们把k+d层的点向k层的四周的点连+oo边,也就是说如果我们割掉了一条边,就不能选择+oo的边连接的上面的边,因为选择了这条边,如果再选择上面的边的话,就不能构成割了,因为流还是可以经过那条+oo的边流回来。其实类比一下最大权独立集的话,这条+oo的边的意义就是选了某个点以后,就不能选和它相差超过d的点了。
来自:http://www.cnblogs.com/zig-zag/archive/2013/05/13/3076563.html
这样子的话,割掉超过d的边,还是割不断st到ed的路径的。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define Maxn 50 9 #define INF 0xfffffff 10 11 int mymin(int x,int y) {return x<y?x:y;} 12 13 int num[Maxn][Maxn][Maxn],v[Maxn][Maxn][Maxn]; 14 15 struct node 16 { 17 int x,y,f,next,o; 18 }t[Maxn*Maxn*Maxn*20]; 19 int len,first[Maxn*Maxn*Maxn]; 20 21 void ins(int x,int y,int f) 22 { 23 t[++len].x=x;t[len].y=y;t[len].f=f; 24 t[len].next=first[x];first[x]=len;t[len].o=len+1; 25 t[++len].x=y;t[len].y=x;t[len].f=0; 26 t[len].next=first[y];first[y]=len;t[len].o=len-1; 27 } 28 29 int st,ed; 30 int dis[Maxn*Maxn*Maxn]; 31 queue<int > q; 32 bool bfs() 33 { 34 for(int i=1;i<=ed;i++) dis[i]=-1; 35 while(!q.empty()) q.pop(); 36 dis[st]=0;q.push(st); 37 while(!q.empty()) 38 { 39 int x=q.front(); 40 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 41 { 42 int y=t[i].y; 43 if(dis[y]==-1) 44 { 45 dis[y]=dis[x]+1; 46 q.push(y); 47 } 48 } 49 q.pop(); 50 } 51 if(dis[ed]==-1) return 0; 52 return 1; 53 } 54 55 int ffind(int x,int flow) 56 { 57 if(x==ed) return flow; 58 int now=0; 59 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 60 { 61 int y=t[i].y; 62 if(dis[y]==dis[x]+1) 63 { 64 int a=ffind(y,mymin(flow-now,t[i].f)); 65 t[i].f-=a; 66 t[t[i].o].f+=a; 67 now+=a; 68 } 69 if(now==flow) break; 70 } 71 if(now==0) dis[x]=-1; 72 return now; 73 } 74 75 void output() 76 { 77 for(int i=1;i<=len;i+=2) 78 { 79 printf("%d -> %d %d\n",t[i].x,t[i].y,t[i].f); 80 }printf("\n"); 81 } 82 83 int ans=0; 84 void max_flow() 85 { 86 while(bfs()) 87 { 88 ans+=ffind(st,INF); 89 } 90 printf("%d\n",ans); 91 } 92 93 int main() 94 { 95 int n,m,h,d; 96 scanf("%d%d%d",&n,&m,&h); 97 scanf("%d",&d); 98 int cnt=0; 99 st=n*m*h+1;ed=st+1; 100 for(int k=1;k<=h;k++) 101 { 102 for(int i=1;i<=n;i++) 103 for(int j=1;j<=m;j++) 104 { 105 scanf("%d",&v[i][j][k]); 106 num[i][j][k]=++cnt; 107 if(k!=1) ins(num[i][j][k-1],num[i][j][k],v[i][j][k]); 108 else ins(st,num[i][j][k],v[i][j][k]); 109 if(k==h) ins(num[i][j][k],ed,INF); 110 if(i!=1&&k>d) ins(num[i][j][k],num[i-1][j][k-d],INF); 111 if(i!=n&&k>d) ins(num[i][j][k],num[i+1][j][k-d],INF); 112 if(j!=1&&k>d) ins(num[i][j][k],num[i][j-1][k-d],INF); 113 if(j!=m&&k>d) ins(num[i][j][k],num[i][j+1][k-d],INF); 114 } 115 } 116 max_flow(); 117 return 0; 118 }
2017-03-29 14:57:42