题目链接:
https://www.luogu.org/problemnew/show/P2598
分析:
我们知道此题的目的是将狼和羊分割开,很容易想到狼在S,羊在T中。
首先,我们可以在狼,羊,空地这三者中四连通的连边,流量为1,此时可以表示无篱笆,割一条边就代表建起了长度为1的篱笆。
然后考虑狼如何向S连边呢?
因为狼和S之间的边我们是不能割掉的!
所以把流量赋值为inf即可。
羊和T同理。
然后跑最大流,即为最小割。
代码:
#include<cstdio>
#include<vector>
#include<cstring>
#include<vector>
#include<queue>
#define inf 0x7fffffff
using namespace std;
int dx[5]={0,-1,1,0,0};
int dy[5]={0,0,0,-1,1};
struct edge
{
int to,val,rev;
edge(int _to,int _val,int _rev)
{
to=_to;
val=_val;
rev=_rev;
}
};
vector<edge>e[10005];
void add(int x,int y,int w)
{
e[x].push_back(edge(y,w,e[y].size()));
e[y].push_back(edge(x,0,e[x].size()-1));
}
int s,t;
int d[10005];
bool bfs()
{
queue<int>q;
memset(d,-1,sizeof(d));
d[s]=0;
q.push(s);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=0;i<e[x].size();i++)
{
int y=e[x][i].to;
if(d[y]==-1&&e[x][i].val)
{
q.push(y);
d[y]=d[x]+1;
}
}
}
if(d[t]==-1)return 0;
return 1;
}
int id[105][105];
int dfs(int x,int low)
{
if(x==t||low==0)return low;
int totflow=0;
for(int i=0;i<e[x].size();i++)
{
int y=e[x][i].to;
int rev=e[x][i].rev;
if(d[y]==d[x]+1&&e[x][i].val)
{
int a=dfs(y,min(low,e[x][i].val));
e[x][i].val-=a;
e[y][rev].val+=a;
low-=a;
totflow+=a;
if(low==0)
return totflow;
}
}
if(low!=0)d[x]=-1;
return totflow;
}
int main()
{
int n,m;
int cnt=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
id[i][j]=++cnt;
}
}
s=0,t=cnt+1;
int a;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a);
if(a==2)
{
add(s,id[i][j],inf);
}
else
if(a==1)
{
add(id[i][j],t,inf);
}
for(int k=1;k<=4;k++)
{
int x=i+dx[k];
int y=j+dy[k];
if(x>0&&x<=n&&y>0&&y<=m)
{
add(id[i][j],id[x][y],1);
}
}
}
}
int ans=0;
while(bfs())
{
ans+=dfs(s,inf);
}
printf("%d",ans);
return 0;
}