最小割经典例题
因为我们要把狼和羊隔开
但是在狼和羊的占地上是允许空地存在的所以我们
把狼到空地和羊的地方连一条流量为1的边
把空地到羊的地方连一条流量为1的边
然后S到所有狼连一条为inf的边
羊到T连一条inf的边
然后跑一边最大流
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int N=100003;
const int T=100001;
const int inf=0x7fffffff;
int to[N*2],nxt[N*2],v[N*2],head[N*2];
int q[N];
int dis[N];
int mp[103][103];
int tot=1,ans,n,m;
int xx[4]={0,0,1,-1};
int yy[4]={1,-1,0,0};
void insert(int a,int b,int val){
to[++tot]=b;
nxt[tot]=head[a];
head[a]=tot;
v[tot]=val;
}
void add(int u,int v,int w){
insert(u,v,w);insert(v,u,0);
}
bool bfs(){
memset(dis,-1,sizeof(dis));
int h=0,t=1;
q[0]=0;
dis[0]=0;
while(h!=t){
int now=q[++h];
for(int i=head[now];i;i=nxt[i]){
if(v[i]&&dis[to[i]]==-1){
dis[to[i]]=dis[now]+1;
q[++t]=to[i];
}
}
}
if(dis[T]==-1){
return false;
}else{
return true;
}
}
int dfs(int now,int f){
if(now==T){
return f;
}
int use=0;
for(int i=head[now];i;i=nxt[i]){
if(v[i]&&dis[to[i]]==dis[now]+1){
int w=f-use;
w=dfs(to[i],min(v[i],w));
v[i]-=w;
v[i^1]+=w;
use+=w;
if(use==f){
return f;
}
}
}
if(!use){
dis[now]=-1;
}
return use;
}
void dinic(){
while(bfs()){
ans+=dfs(0,inf);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>mp[i][j];
if(mp[i][j]==1){
add(0,(i-1)*m+j,inf);
}else if(mp[i][j]==2){
add((i-1)*m+j,T,inf);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=0;k<4;k++){
int nowx=i+xx[k],nowy=j+yy[k];
if(nowx<1||nowx>n||nowy>m||nowy<1||mp[i][j]==2){
continue;
}
if(mp[i][j]!=1||mp[nowx][nowy]!=1){
add((i-1)*m+j,(nowx-1)*m+nowy,1);
}
}
}
}
dinic();
cout<<ans<<endl;
return 0;
}