[BZOJ1412][ZJOI2009]狼和羊的故事(最小割)

来源:互联网 发布:手机淘宝卖家从哪进 编辑:程序博客网 时间:2024/05/02 22:21

题目描述

传送门

题解

首先建立源汇,对于每一个为1的点s->i,对于每一个为2的点i->t,然后每个点向它的四周连边。
这样做的原因是无论如何狼和羊不能通过任何道路连通。
最小割即为答案。

代码

#include<iostream>#include<cstring>#include<cstdio>#include<queue>using namespace std;const int max_n=105;const int max_N=1e4+5;const int max_m=2e5+5;const int max_e=max_m*2;const int INF=1e9;int n,m,a[max_n][max_n],N,maxflow;int tot,point[max_N],next[max_e],v[max_e],remain[max_e];int deep[max_N],last[max_N],num[max_N],cur[max_N];queue <int> q;inline void addedge(int x,int y,int cap){    ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=cap;    ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;}inline void bfs(int t){    for (int i=1;i<=N;++i) deep[i]=N; deep[t]=0;    while (!q.empty()) q.pop(); q.push(t);    while (!q.empty()){        int now=q.front(); q.pop();        for (int i=point[now];i!=-1;i=next[i])          if (deep[v[i]]==N&&remain[i^1]){            deep[v[i]]=deep[now]+1;            q.push(v[i]);          }    }}inline int addflow(int s,int t){    int now=t,ans=INF;    while (now!=s){        ans=min(ans,remain[last[now]]);        now=v[last[now]^1];    }    now=t;    while (now!=s){        remain[last[now]]-=ans;        remain[last[now]^1]+=ans;        now=v[last[now]^1];    }    return ans;}inline void isap(int s,int t){    bfs(t);    for (int i=1;i<=N;++i) ++num[deep[i]];    for (int i=1;i<=N;++i) cur[i]=point[i];    int now=s;    while (deep[s]<N){        if (now==t){            maxflow+=addflow(s,t);            now=s;        }        bool has_find=false;        for (int i=cur[now];i!=-1;i=next[i])          if (deep[v[i]]+1==deep[now]&&remain[i]){            has_find=true;            cur[now]=i;            last[v[i]]=i;            now=v[i];            break;          }        if (!has_find){            int minn=N-1;            for (int i=point[now];i!=-1;i=next[i])              if (remain[i]) minn=min(minn,deep[v[i]]);            if (!(--num[deep[now]])) break;            ++num[deep[now]=minn+1];            cur[now]=point[now];            if (now!=s) now=v[last[now]^1];        }    }}int main(){    tot=-1;    memset(point,-1,sizeof(point));    memset(next,-1,sizeof(next));    scanf("%d%d",&n,&m);    for (int i=1;i<=n;++i)      for (int j=1;j<=m;++j)        scanf("%d",&a[i][j]);    N=n*m+2;    for (int i=1;i<=n;++i)      for (int j=1;j<=m;++j){        int num=(i-1)*m+j;        if (a[i][j]==1) addedge(1,1+num,INF);        else if (a[i][j]==2) addedge(1+num,N,INF);        if (i!=1){            int num1=(i-2)*m+j;            addedge(1+num,1+num1,1);        }        if (j!=1){            int num1=num-1;            addedge(1+num,1+num1,1);        }        if (i!=n){            int num1=i*m+j;            addedge(1+num,1+num1,1);        }        if (j!=m){            int num1=num+1;            addedge(1+num,1+num1,1);        }      }    isap(1,N);    printf("%d\n",maxflow);}

总结

网络流再RE撞死算了。

0 0
原创粉丝点击