bzoj 3144 [Hnoi2013]切糕
最小割。
题意简化一下就是:给一个矩阵,每个点给出一些带编号的选择,每个选择有权值,现在对于每个点做出一个选择,使得相邻点的选择的编号差小于等于d,并且使总权值最大。
首先考虑没有编号差小于等于d的限制,将一个点拆成选择个点,对于一个点的所有选择点,连成一条链,权值反应在边上,首尾与S,T相连,这样求一个最小割就是答案。
再考虑有了限制,某个点选了第i个选择,与它相邻的点就必须选在[i-d,i+d]中的选择。从当前点的i号点向相邻点的i-d号点连一条正无穷的边,再求最小割就好了。
这时如果割掉i的边,那么存在一条流从当前点i号点流向相邻点i-d号点,相邻点的i+d+1号点流向当前点的i+1号点,这样就保证选了i相邻点必须选[i-d,i+d]。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 const int dian=70005; 8 const int bian=500005; 9 const int INF=0x3f3f3f3f; 10 int h[dian],nxt[bian],ver[bian],val[bian],ch[dian],cr[dian]; 11 int n,m,hh,tot,d,aa; 12 int S,T; 13 int bh(int a,int b,int c){ 14 return (a-1)*m*hh+(b-1)*hh+c; 15 } 16 void add(int a,int b,int c){ 17 tot++;ver[tot]=b;val[tot]=c;nxt[tot]=h[a];h[a]=tot; 18 tot++;ver[tot]=a;val[tot]=0;nxt[tot]=h[b];h[b]=tot; 19 } 20 bool tell(){ 21 memset(ch,-1,sizeof(ch)); 22 queue<int>q; 23 q.push(S); 24 ch[S]=0; 25 while(!q.empty()){ 26 int t=q.front(); 27 q.pop(); 28 for(int i=h[t];i;i=nxt[i]) 29 if(ch[ver[i]]==-1&&val[i]){ 30 ch[ver[i]]=ch[t]+1; 31 q.push(ver[i]); 32 } 33 } 34 return ch[T]!=-1; 35 } 36 int zeng(int a,int b){ 37 if(a==T) 38 return b; 39 int r=0; 40 for(int i=cr[a];i&&b>r;i=nxt[i]) 41 if(ch[ver[i]]==ch[a]+1&&val[i]){ 42 int t=zeng(ver[i],min(b-r,val[i])); 43 val[i]-=t,r+=t,val[i^1]+=t; 44 if(val[i]) 45 cr[a]=i; 46 } 47 if(!r) 48 ch[a]=-1; 49 return r; 50 } 51 int dinic(){ 52 int r=0,t; 53 while(tell()){ 54 for(int i=1;i<=n*m*hh+2;i++) 55 cr[i]=h[i]; 56 while(t=zeng(S,INF)) 57 r+=t; 58 } 59 return r; 60 } 61 int main(){ 62 memset(h,0,sizeof(h)); 63 memset(nxt,0,sizeof(nxt)); 64 tot=1; 65 scanf("%d%d%d",&n,&m,&hh); 66 S=n*m*hh+1,T=n*m*hh+2; 67 for(int i=1;i<=n;i++) 68 for(int j=1;j<=m;j++) 69 add(S,bh(i,j,1),INF); 70 scanf("%d",&d); 71 for(int i=1;i<=hh;i++) 72 for(int j=1;j<=n;j++) 73 for(int k=1;k<=m;k++){ 74 scanf("%d",&aa); 75 if(i!=hh) 76 add(bh(j,k,i),bh(j,k,i+1),aa); 77 else 78 add(bh(j,k,i),T,aa); 79 } 80 for(int i=1;i<=n;i++) 81 for(int j=1;j<=m;j++){ 82 if(i-1>=1){ 83 for(int k=1;k<=d;k++) 84 add(bh(i,j,k),bh(i-1,j,1),INF); 85 for(int k=d+1;k<=hh;k++) 86 add(bh(i,j,k),bh(i-1,j,k-d),INF); 87 } 88 if(i+1<=n){ 89 for(int k=1;k<=d;k++) 90 add(bh(i,j,k),bh(i+1,j,1),INF); 91 for(int k=d+1;k<=hh;k++) 92 add(bh(i,j,k),bh(i+1,j,k-d),INF); 93 } 94 if(j-1>=1){ 95 for(int k=1;k<=d;k++) 96 add(bh(i,j,k),bh(i,j-1,1),INF); 97 for(int k=d+1;k<=hh;k++) 98 add(bh(i,j,k),bh(i,j-1,k-d),INF); 99 } 100 if(j+1<=m){ 101 for(int k=1;k<=d;k++) 102 add(bh(i,j,k),bh(i,j+1,1),INF); 103 for(int k=d+1;k<=hh;k++) 104 add(bh(i,j,k),bh(i,j+1,k-d),INF); 105 } 106 } 107 printf("%d",dinic()); 108 return 0; 109 }