P2598 [ZJOI2009]狼和羊的故事(网络流)
源点和所有狼连 $inf$ 的边
所有羊和汇点连 $inf$ 的边
所有点向四周连 $1$ 的边
这样所有狼和羊之间的边都被割掉了
统计最小割就好辣
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; #define N 100005 #define inf 100000005 const int d1[4]={1,0,-1,0}; const int d2[4]={0,1,0,-1}; int n,m,w,d[N],cur[N],S,T; bool vis[N]; queue <int> h; int cnt=1,hd[N],nxt[N],ed[N],poi[N],val[N]; inline void adde(int x,int y,int v){ nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt, ed[x]=cnt, poi[cnt]=y, val[cnt]=v; } inline void link(int x,int y,int v){adde(x,y,v),adde(y,x,0);} inline int id(int x,int y){return (x-1)*m+y;} bool bfs(){ memset(vis,0,sizeof(vis)); h.push(S); vis[S]=1; while(!h.empty()){ int x=h.front(); h.pop(); for(int i=hd[x];i;i=nxt[i]){ int to=poi[i]; if(!vis[to]&&val[i]) vis[to]=1,d[to]=d[x]+1,h.push(to); } }return vis[T]; } int dfs(int x,int a){ if(x==T||a==0) return a; int F=0,f; for(int i=cur[x];i;i=nxt[i]){ cur[x]=i;int to=poi[i]; if(d[to]==d[x]+1&&(f=dfs(to,min(a,val[i])))>0) a-=f,F+=f,val[i]-=f,val[i^1]+=f; }return F; } int dinic(){ int re=0; while(bfs()){ for(int i=1;i<=T;++i) cur[i]=hd[i]; re+=dfs(S,inf); }return re; } void draw(int x,int y){ scanf("%d",&w); int p=id(x,y); for(int i=0;i<4;++i){ int r1=x+d1[i],r2=y+d2[i]; if(r1<1||r1>n||r2<1||r2>m) continue; link(p,id(r1,r2),1); } if(w==1) link(S,p,inf); if(w==2) link(p,T,inf); } int main(){ scanf("%d%d",&n,&m); S=n*m+1; T=S+1; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) draw(i,j); printf("%d",dinic()); return 0; }