【[ZJOI2009]狼和羊的故事】最大流最小割
由于看完最大流就跟着做到了最小割的题。。。一道题愣是看了一个多小时没有思路,看标签才发现我还有知识欠缺---》最小割走起!
洛谷传送门:https://www.luogu.org/problemnew/show/P2598
/*由于本蒟蒻刚刚学最小割,这里就不单纯写本题题解,同时放出三个定理来(from root's jiangyi)
定理一:如果f是网络中的一个流,CUT(S,T)是任意一个割,那么f的值等于正向割边的流量与负向割边的流量之差。(最大流流量不超过任何割容量)
定理2:在任何网络中,如果f是一个流,CUT(S,T)是一个割,且f的值等于割CUT(S,T)的容量,那么f是一个最大流,CUT(S,T)是一个最小割(容量最小的割)。
定理3:最大流最小割定理:在任何的网络中,最大流的值等于最小割的容量。
*/
其实这是一道UVA1515的简化版,luogu传送门https://www.luogu.org/problemnew/show/UVA1515
翻译在这道题讨论区里面,原版本里面除了划分以外还有修改地盘操作,但稍加思索也并不难,看向本题。
这道题很显然的一道最大流最小割板子题。我们最后就是求将羊和狼割成两块的最小割,直接S连所有的羊,狼连所有的T,容量为inf,然后将羊与狼连接,容量为1就好啦!
值得斟酌的是里面的0.稍加思索之后,我们把0当做羊来连边,因为我们看羊的连边即是连向0和狼,而0的连边也是连向0和狼,但0不与S相连,容量这里都为1。
大致最后的图是 : S-》羊-》0-》狼-》T
搞定!
//S->yang-0-> lang ->T #include<bits/stdc++.h> #define id(x,y) ((x-1)*m+y) using namespace std; const int inf=0x3f3f3f3f; int n,m,S,T; int dx[4]={0,0,-1,1}; int dy[4]={1,-1,0,0}; int tu[105][105]; int la[10005],nt[100005],en[100005],v[100005],owo=1; void addedge(int a,int b,int c) { en[++owo]=b; nt[owo]=la[a]; la[a]=owo; v[owo]=c; } int dis[10005],cnt[10005]; int sap(int x,int flow) { if(x==T) return flow; int dlt=0,tmp; for(int it=la[x];it;it=nt[it]) { if(v[it]&&dis[x]==dis[en[it]]+1) { tmp=sap(en[it],min(flow-dlt,v[it])); dlt+=tmp; v[it]-=tmp; v[it^1]+=tmp; if(dlt==flow||dis[S]>=n*m+2) return dlt; } } if(dis[S]>=n*m+2) return dlt; cnt[dis[x]]--; if(!cnt[dis[x]]) dis[S]=n*m+2; dis[x]++; cnt[dis[x]]++; return dlt; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&tu[i][j]); S=n*m+1; T=n*m+2; int nx,ny; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(tu[i][j]==2) { addedge( id(i,j) ,T, 0x3f3f3f3f ); addedge( T,id(i,j), 0); } else { if(tu[i][j]==1) { addedge( S,id(i,j) ,0x3f3f3f3f ); addedge( id(i,j),S,0); } for(int k=0;k<4;k++) { nx=i+dx[k]; ny=j+dy[k]; if(nx>=1&&nx<=n&&ny>=1&&ny<=m) { if(tu[nx][ny]==0||tu[nx][ny]==2) { addedge(id(i,j),id(nx,ny),1); addedge( id(nx,ny),id(i,j),0 ); } } } } } int ans=0; while(dis[S]<n*m+2) { ans+=sap(S,0x3f3f3f3f); } printf("%d",ans); }