3144: [Hnoi2013]切糕
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1495 Solved: 819
[Submit][Status][Discuss]
Description
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
1
6 1
6 1
2 6
2 6
Sample Output
6
HINT
最佳切面的f为f(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1
Source
分析:
限制距离模型:
可以把题意看成有p*q个网格,每个网格有r个点,要在每个格子中选一个点,并且相邻的格子选择的点距离不超过d,求最小代价...
考虑如果没有距离限制怎么建图...把每个格子拆成r个点,串成一条链和ST相连,求最小割就是答案...
现在有了距离限制...怎么办??最常用的限制方法就是添加容量为+∞的边...
我们把(i,j,k)向(i',j',k-d)(相邻的格子)连边...这个正确性画一下图YY一下就好...
代码:
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 //by NeighThorn 6 #define inf 0x3f3f3f3f 7 using namespace std; 8 9 const int maxn=100000+5,maxm=1000000+5; 10 11 int n,m,h,d,S,T,cnt,hd[maxn],fl[maxm],to[maxm],nxt[maxm],pos[maxn]; 12 13 int mv[4][2]={0,1,0,-1,1,0,-1,0}; 14 15 inline bool bfs(void){ 16 memset(pos,-1,sizeof(pos)); 17 int head=0,tail=0,q[maxn]; 18 q[0]=S,pos[S]=0; 19 while(head<=tail){ 20 int top=q[head++]; 21 for(int i=hd[top];i!=-1;i=nxt[i]) 22 if(pos[to[i]]==-1&&fl[i]) 23 pos[to[i]]=pos[top]+1,q[++tail]=to[i]; 24 } 25 return pos[T]!=-1; 26 } 27 28 inline int find(int v,int f){ 29 if(v==T) 30 return f; 31 int res=0,t; 32 for(int i=hd[v];i!=-1&&f>res;i=nxt[i]) 33 if(pos[to[i]]==pos[v]+1&&fl[i]) 34 t=find(to[i],min(fl[i],f-res)),res+=t,fl[i]-=t,fl[i^1]+=t; 35 if(!res) 36 pos[v]=-1; 37 return res; 38 } 39 40 inline int dinic(void){ 41 int res=0,t; 42 while(bfs()) 43 while(t=find(S,inf)) 44 res+=t; 45 return res; 46 } 47 48 inline void add(int s,int x,int y){ 49 fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++; 50 fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++; 51 } 52 53 signed main(void){ 54 // freopen("in.txt","r",stdin); 55 memset(hd,-1,sizeof(hd)); 56 scanf("%d%d%d%d",&n,&m,&h,&d); 57 S=0,T=n*m*h+1; 58 for(int k=1,x;k<=h;k++) 59 for(int i=1;i<=n;i++) 60 for(int j=1;j<=m;j++){ 61 scanf("%d",&x); 62 if(k==1) 63 add(x,S,((i-1)*m+j-1)*h+k); 64 else 65 add(x,((i-1)*m+j-1)*h+k-1,((i-1)*m+j-1)*h+k); 66 if(k==h) 67 add(inf,((i-1)*m+j-1)*h+k,T); 68 } 69 for(int i=1;i<=n;i++) 70 for(int j=1;j<=m;j++) 71 for(int k=d+1;k<=h;k++) 72 for(int t=0;t<4;t++){ 73 int x=i+mv[t][0],y=j+mv[t][1]; 74 if(x>=1&&x<=n&&y>=1&&y<=m) 75 add(inf,((i-1)*m+j-1)*h+k,((x-1)*m+y-1)*h+k-d); 76 } 77 printf("%d ",dinic()); 78 return 0; 79 }//Cap ou pas cap. Cap.
By NeighThorn