【JZOJ1637】【ZJOI2009】The story of wolf and sheep (minimum cut)

Problem

  Given a matrix grid of n*m (n, m≤100) surrounded by fences, each of which is a wolf, a sheep or grass, it is required to build a fence on the boundary of some grids, so that the wolf cannot go to the sheep's place. Find the shortest length of the fence.

Solution

  Tomorrow will be GDOI, but I am not very familiar with the network flow, so I take this problem to practice.
  Consider conversion models. Create a super source S and a super sink T. Connect an edge with infinite capacity from S to all wolves, indicating that one wolf can threaten many sheep; connect an edge with capacity 1 from all sheep squares to all surrounding non-wolf squares, indicating that wolves can walk there; All sheep connect an edge with infinite capacity to T.
  Then we want to cut the least edge, so according to the maximum flow minimum cut theorem, run the maximum flow directly. Here I use the combined version of SAP and dinic. See the code for specific implementation.
  time complexity: O ( overtake sound speed )

Code

#include <cstdio>
#include <algorithm>
using namespace std;
#define fo(i,a,b) for(i=a;i<=b;i++)
const int N=110,v[2][2]={{-1,0},{0,-1}},NO=N*N,M=NO*6,inf=0x7FFFFFFF;
int i,j,k,n,m,tot,a[N][N],x,y,tov[M][2],len[M],next[M],last[N][N],node,dis[N][N],cur[N][N],GAP[NO],ans;

inline void link(int xi,int xj,int yi,int yj,int z)
{
    tov[++tot][0]=yi;tov[tot][1]=yj;
    len[tot]=z;
    next[tot]=last[xi][xj];
    last[xi][xj]=tot;
}
inline void Link(int xi,int xj,int yi,int yj,int z)
{
    link(xi,xj,yi,yj,z);
    link(yi,yj,xi,xj,0);
}
inline bool check(int xi,int xj,int yi,int yj)
{
    return a[xi][xj]==1||!a[xi][xj]&&a[yi][yj]==2;
}
void scan()
{
    scanf("%d%d",&n,&m);
    tot=1;
    fo(i,1,n)
        fo(j,1,m)
        {
            scanf("%d",&a[i][j]);
            switch(a[i][j])
            {
                case 1:Link(0,0,i,j,inf);break;
                case 2:Link(i,j,0,1,inf);break;
            }
            fo(k,0,1)
            {
                x=i+v[k][0];y=j+v[k][1];
                if(x&&y)
                    if(check(i,j,x,y))Link(i,j,x,y,1);
                    else
                    if(check(x,y,i,j))Link(x,y,i,j,1);
                    else
                    if(!a[i][j]&&!a[x][y])link(i,j,x,y,1),link(x,y,i,j,1);
            }
        }
    GAP[0]=node=n*m+2;  
}

int flow(int xi,int xj,int Flow)//目前在点(xi,xj),有流量Flow,求流至T的流量
{
    if(!xi&&xj)return Flow;//有可行流,返回流量
    int i,yi,yj,have=0,now;//have表示已流多少流量
    for(i=cur[xi][xj];i;i=next[i])//从当前弧开始枚举
    {
        yi=tov[i][0];yj=tov[i][1];
        if(dis[yi][yj]+1==dis[xi][xj]&&len[i])//有允许弧
        {
            cur[xi][xj]=i;//更新当前弧
            now=flow(yi,yj,min(len[i],Flow-have));//计算流量
            len[i]-=now;len[i^1]+=now;//更新边权,满足反对称性
            have+=now;
            if(have==Flow)return have;//如果已满流,退出
        }
    }
    cur[xi][xj]=last[xi][xj];//当前弧赋值为边集数组第一条弧
    if(!--GAP[dis[xi][xj]])dis[0][0]=node;//GAP优化
    GAP[++dis[xi][xj]]++;//更新距离标号,其实可以这么更新
    return have;
}

int main()
{
    scan();
    while(dis[0][0]<node)ans+=flow(0,0,1<<30);
    printf("%d",ans);
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325563634&siteId=291194637