正题
评测记录:
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);
}