BZOJ3144: [Hnoi2013]切糕
题解;
WJMZBMR:
考虑网络流,
我们构造一个P*Q*(R+1)的点阵,用(i,j,k)表示一个点
那么(i,j,k) -> (i,j,k+1) 的流量为原图中(i,j,k)的不和谐值。
S向所有底层连无穷边,所有顶层向T连无穷边。
那么(i,j,k) -> (i,j,k+1)被割表示f(i,j)=k。。。
同时我们让(i,j,k) -> (i',j',k-D)连一条无穷边,就能保证相邻两个不超过D了。
(i,j)与(i',j')相邻。
意思是什么呢?
首先每个点向下连容量为其权值的边,意思是这一竖线只能选一个,之前的划在s割,之后的在t割。
然后我们连边 (i,j,k)到(i',j',k-d)意思就是 这两个点必须同割!不同割会发生什么情况
(i‘,j’)在k-d高度以前就选了,而(i,j)在k还没选。或者返回来,高度超过了D所以不合法。
这样就保证了合法性。
代码:
1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include<iostream> 12 13 #include<vector> 14 15 #include<map> 16 17 #include<set> 18 19 #include<queue> 20 21 #include<string> 22 23 #define inf 1000000000 24 25 #define maxn 50*50*50 26 27 #define maxm 20*50*50*50 28 29 #define eps 1e-10 30 31 #define ll long long 32 33 #define pa pair<int,int> 34 35 #define for0(i,n) for(int i=0;i<=(n);i++) 36 37 #define for1(i,n) for(int i=1;i<=(n);i++) 38 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 40 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 42 43 #define for4(i,x) for(int i=head[x],y;i;i=e[i].next) 44 45 #define mod 1000000007 46 47 using namespace std; 48 49 inline int read() 50 51 { 52 53 int x=0,f=1;char ch=getchar(); 54 55 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 56 57 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 58 59 return x*f; 60 61 } 62 int D,H,n,m,s,t,maxflow,tot,head[maxn],cur[maxn],h[maxn],num[50][50][50]; 63 queue<int>q; 64 struct edge{int go,next,v;}e[maxm]; 65 inline void add(int x,int y,int v) 66 { 67 e[++tot]=(edge){y,head[x],v};head[x]=tot; 68 e[++tot]=(edge){x,head[y],0};head[y]=tot; 69 } 70 bool bfs() 71 { 72 for(int i=s;i<=t;i++)h[i]=-1; 73 q.push(s);h[s]=0; 74 while(!q.empty()) 75 { 76 int x=q.front();q.pop(); 77 for(int i=head[x];i;i=e[i].next) 78 if(e[i].v&&h[e[i].go]==-1) 79 { 80 h[e[i].go]=h[x]+1;q.push(e[i].go); 81 } 82 } 83 return h[t]!=-1; 84 } 85 int dfs(int x,int f) 86 { 87 if(x==t) return f; 88 int tmp,used=0; 89 for(int i=cur[x];i;i=e[i].next) 90 if(e[i].v&&h[e[i].go]==h[x]+1) 91 { 92 tmp=dfs(e[i].go,min(e[i].v,f-used)); 93 e[i].v-=tmp;if(e[i].v)cur[x]=i; 94 e[i^1].v+=tmp;used+=tmp; 95 if(used==f)return f; 96 } 97 if(!used) h[x]=-1; 98 return used; 99 } 100 void dinic() 101 { 102 maxflow=0; 103 while(bfs()) 104 { 105 for (int i=s;i<=t;i++)cur[i]=head[i];maxflow+=dfs(s,inf); 106 } 107 } 108 const int dx[4]={0,0,1,-1}; 109 const int dy[4]={1,-1,0,0}; 110 111 int main() 112 113 { 114 115 freopen("input.txt","r",stdin); 116 117 freopen("output.txt","w",stdout); 118 n=read();m=read();H=read();D=read(); 119 for1(k,H+1)for1(i,n)for1(j,m)num[i][j][k]=++tot; 120 s=0;t=tot+1; 121 tot=1; 122 for1(k,H)for1(i,n)for1(j,m)add(num[i][j][k],num[i][j][k+1],read()); 123 for1(i,n)for1(j,m)add(s,num[i][j][1],inf),add(num[i][j][H+1],t,inf); 124 for1(k,H)for1(i,n)for1(j,m)for0(l,3) 125 { 126 int x=i+dx[l],y=j+dy[l]; 127 if(x<1||x>n||y<1||y>m)continue; 128 //if(k+D<H+2)add(num[i][j][k],num[x][y][k+D],inf); 129 if(k-D>0)add(num[i][j][k],num[x][y][k-D],inf); 130 } 131 dinic(); 132 cout<<maxflow<<endl; 133 134 return 0; 135 136 }