我个人的理解:
可以先对原图进行建模为下图
其左端是狼,右端为羊,中间是连接狼和羊的路
现在为了让狼吃不到样,就要隔断狼和羊之间的连接
也就是
在这里,我们需要隔断狼和羊之间的连接,也就是转化成最小割问题
很明显,这里的路权均为1
然后分别建立源点和汇点,分别连接狼与羊,边权为inf,进行求解最小割即可
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 2e5+7;
int dir[4][4] = {{1,0},{0,1},{-1,0},{0,-1}};
struct node{
int to,from;
ll w;
}edge[MAXN];
class Dinic:node{
public:
const int inf =0x3f3f3f3f;
int head[MAXN],now[MAXN],cnt=1,n,s,t;//点数,源点,汇点
int dep[MAXN],ans;
void Add(int u,int v,ll w)
{
cnt++;
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].from = head[u];
head[u] = cnt;
}
void add(int u,int v,int w){
Add(u,v,w);
Add(v,u,0);
}
int bfs()
{
for(int i=1;i<=n;i++)
dep[i] = inf;
queue<int>q;
q.push(s);
dep[s] = 0;
now[s] = head[s];
while(!q.empty())
{
int so = q.front();
q.pop();
for(int i=head[so];i;i=edge[i].from)
{
int to = edge[i].to;
if(edge[i].w&&dep[to] == inf)
{
q.push(to);
now[to] = head[to];
dep[to] = dep[so]+1;
if(to==t) return 1;
}
}
}
return 0;
}
int dfs(int x,ll sum)
{
if(x==t)return sum;
ll k,res=0;
for(int i=now[x];i&∑i = edge[i].from)
{
now[x] = i;//当前弧优化
int to = edge[i].to;
if(edge[i].w&&dep[to]==dep[x]+1)
{
k = dfs(to,min(sum,edge[i].w));
if(k==0) dep[to] = inf;
edge[i].w-=k;
edge[i^1].w+=k;
res+=k;//流量和
sum-=k;//剩余流量
}
}
return res;
}
int dini(){
while(bfs())ans+=dfs(s,inf);
return ans;
}
};
Dinic d;
int n,m;
int cal(int x,int y)
{
return (x-1)*m+y;
}
int a[105][105];
int main()
{
cin>>n>>m;
d.n = n*m+2;
d.s = n*m+1;d.t = n*m+2;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]==1)d.add(d.s,cal(i,j),d.inf);
if(a[i][j]==2)d.add(cal(i,j),d.t,d.inf);
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
{
int tx=i+dir[k][0];
int ty=j+dir[k][1];
if(tx<=n and ty<=m and tx>=1 and ty>=1)
d.add(cal(i,j),cal(tx,ty),1);
}
cout<<d.dini()<<endl;
}