正题
评测记录:
https://www.luogu.org/recordnew/lists?uid=52918&pid=P2598
大意
有n*m的矩阵,里面有羊和狼(也有可能是空),可以在两个格子之间围上篱笆让两个格子不能互相到达,要求狼的格子不能和羊的格子在同一个联通块上。求最少篱笆数。
解题思路
将每一个格子当成一个点,然后相邻的格子连接1(表示可以相互到达,并可以用篱笆代价1阻隔),然后源点连狼inf,汇点连羊inf(不可以去掉),之后求最小割。
构图:
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MN 10005
#define inf 2147483647
using namespace std;
struct line{
int to,w,next;
}a[MN*10];
int n,m,c,ls[MN],d[MN],maxs,e;
int head,tail,state[MN],tot,s;
void addl(int x,int y,int w)
{
a[tot].to=y;a[tot].next=ls[x];
a[tot].w=w;ls[x]=tot++;
a[tot].to=x;a[tot].next=ls[y];
a[tot].w=0;ls[y]=tot++;
}
int num(int x,int y)
{
if (x<1||y<1||x>n||y>m) return e+1;
else return (x-1)*m+y;
}
bool bfs()
{
head=0;tail=1;
memset(d,-1,sizeof(d));
d[s]=0;state[1]=s;
do
{
head++;
int x=state[head];
for (int q=ls[x];q;q=a[q].next)
{
int y=a[q].to;
if (a[q].w>0 && d[y]==-1)
{
d[y]=d[x]+1;
state[++tail]=y;
if (y==e) return true;
}
}
}
while (head<tail);
return false;
}
int dinic(int x,int flow)
{
int rest=0,k;
if (x==e) return flow;
for (int q=ls[x];q;q=a[q].next)
{
int y=a[q].to;
if (a[q].w>0 && d[y]==d[x]+1)
{
rest+=(k=dinic(y,min(a[q].w,flow-rest)));
a[q].w-=k;
a[q^1].w+=k;
if (rest==flow) return flow;
}
}
if (!rest) d[x]=0;
return rest;
}
int main()
{
tot=2;
scanf("%d%d",&n,&m);
s=num(n,m)+1;e=s+1;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
scanf("%d",&c);
addl(num(i,j),num(i+1,j),1);
addl(num(i,j),num(i,j+1),1);
addl(num(i,j),num(i-1,j),1);
addl(num(i,j),num(i,j-1),1);//与周围连边
if (c==1) addl(s,num(i,j),inf);//狼
if (c==2) addl(num(i,j),e,inf);//羊
}
while (bfs()) maxs+=dinic(s,inf);
printf("%d",maxs);
}