【[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);
}

浙公网安备 33010602011771号