洛谷 P2598 [ZJOI2009]狼和羊的故事 最小割

题目描述

“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。

输入输出格式

输入格式:
文件的第一行包含两个整数n和m。接下来n行每行m个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。

输出格式:
文件中仅包含一个整数ans,代表篱笆的最短长度。

输入输出样例

输入样例#1:
2 2
2 2
1 1
输出样例#1:
2
说明

数据范围

10%的数据 n,m≤3

30%的数据 n,m≤20

100%的数据 n,m≤100

分析:很显然的最小割嘛。S连羊,羊连空地,空地连狼,狼连T就可以了。

然后dfs一个垃圾错误搞得很烦。

代码:

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>

const int inf=0x3f3f3f3f;
const int dx[4]={1,0,-1,0};
const int dy[4]={0,1,0,-1};

using namespace std;

int n,m,s,t,cnt;
int a[105][105];
int ls[20001];
int dis[20001];

queue <int> q;

struct edge{
    int y,w,op,next;
}g[100002];

int op(int x,int y)
{
    return (x-1)*m+y;
}

void add(int x,int y,int w)
{
    g[++cnt]=(edge){y,w,cnt+1,ls[x]};
    ls[x]=cnt;
    g[++cnt]=(edge){x,0,cnt-1,ls[y]};
    ls[y]=cnt;
}

bool bfs()
{
    for (int i=s;i<=t;i++) dis[i]=0;
    dis[s]=1;
    while (!q.empty()) q.pop();
    q.push(s);
    while (!q.empty())
    {
        int u=q.front();
        q.pop();
        for (int i=ls[u];i>0;i=g[i].next)
        {
            int v=g[i].y;
            if ((dis[v]==0) && (g[i].w))
            {
                dis[v]=dis[u]+1;
                if (v==t) return true;
                q.push(v);
            }
        }
    }
    return false;
}

int dfs(int x,int maxf)
{
    if ((x==t) || (maxf==0)) return maxf;
    int ret=0;
    for (int i=ls[x];i>0;i=g[i].next)
    {
        int y=g[i].y;
        if ((dis[x]+1==dis[y]) && (g[i].w))
        {
            int f=dfs(y,min(maxf-ret,g[i].w));
            g[i].w-=f;
            g[g[i].op].w+=f;
            ret+=f;
        }
    }
    return ret;
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
    }   
    s=0; t=n*m+1;   
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
        {
            if (a[i][j]==1) add(s,op(i,j),inf);
            if (a[i][j]==2) add(op(i,j),t,inf);
            if ((a[i][j]==1) || (a[i][j]==0))
            {
                for (int k=0;k<=3;k++)
                {
                    int x=i+dx[k],y=j+dy[k];
                    if ((x>0) && (y>0) && (x<=n) && (y<=m))
                    {
                        if ((a[x][y]==2) || (a[x][y]==0))
                        add(op(i,j),op(x,y),1);
                    }
                }
            }
        }
    }   
    int ans=0;
    while (bfs()) 
     ans+=dfs(s,inf);
    printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/81041924
今日推荐