思路:
最小割;
狼作为一个点集a,空领地作为点集b,羊作为点集c;
s向a连边,c向t连边,a向b连边,b向b连边,b向c连边;
如何理解最小割?
a,c之间割掉最少的路径(栅栏)使其没有通路;
来,上代码:
#include <cstdio>
#include <cstring>
#include <iostream> using namespace std; #define maxn 20005
#define maxm 200005
#define INF 0x7ffffff const int dx[]={,-,,,};
const int dy[]={,,,,-}; int s,t,cnt=,size,que[maxm],deep[maxn],n,m;
int head[maxn],E[maxm],V[maxm],F[maxm],map[][]; inline void edge_add(int u,int v,int f)
{
E[++cnt]=head[u],V[cnt]=v,F[cnt]=f,head[u]=cnt;
E[++cnt]=head[v],V[cnt]=u,F[cnt]=,head[v]=cnt;
} bool bfs()
{
for(int i=s;i<=t;i++) deep[i]=-;
int h=,tail=;que[h]=s,deep[s]=;
while(h<tail)
{
int now=que[h++];
for(int i=head[now];i;i=E[i])
{
if(deep[V[i]]<&&F[i]>)
{
deep[V[i]]=deep[now]+;
if(V[i]==t) return true;
que[tail++]=V[i];
}
}
}
return false;
} int flowing(int now,int flow)
{
if(now==t||flow<=) return flow;
int oldflow=;
for(int i=head[now];i;i=E[i])
{
if(deep[V[i]]==deep[now]+&&F[i]>)
{
int pos=flowing(V[i],min(flow,F[i]));
F[i]-=pos,F[i^]+=pos;
flow-=pos,oldflow+=pos;
if(flow==) return oldflow;
}
}
if(oldflow==) deep[now]=-;
return oldflow;
} int main()
{
scanf("%d%d",&n,&m);
size=n*m,t=size+;
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++) scanf("%d",&map[i][j]);
}
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
if(map[i][j]==) edge_add(s,(i-)*m+j,INF);
if(map[i][j]==) edge_add((i-)*m+j,t,INF);
for(int v=;v<=;v++)
{
int xx=i+dx[v],yy=j+dy[v];
if(xx>&&xx<=n&&yy>&&yy<=m)
{
if(map[i][j]!=||map[xx][yy]!=) edge_add((i-)*m+j,(xx-)*m+yy,);
}
}
}
}
int ans=;
while(bfs()) ans+=flowing(s,INF);
cout<<ans;
return ;
}