P2598 [ZJOI2009]狼和羊的故事(网络流)

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;
}

猜你喜欢

转载自www.cnblogs.com/kafuuchino/p/10771257.html