【bzoj1412】[ZJOI2009]狼和羊的故事 网络流最小割

题目描述

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

输入

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

输出

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

样例输入

2 2
2 2
1 1

样例输出

2


题解

比较裸的最小割问题

狼点向周围的空地点和羊点连边,空地向周围的空地和羊点连边。S到狼点、羊点到T连容量为inf的边。

然后跑最小割。

#include <cstdio>
#include <cstring>
#include <queue>
#define N 10010
#define inf 0x3fffffff
using namespace std;
queue<int> q;
int map[110][110] , num[110][110] , head[N] , to[N << 3] , val[N << 3] , next[N << 3] , cnt = 1 , s , t , dis[N];
void add(int x , int y , int z)
{
    to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
    to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
}
bool bfs()
{
    int x , i;
    while(!q.empty()) q.pop();
    memset(dis , 0 , sizeof(dis));
    dis[s] = 1 , q.push(s);
    while(!q.empty())
    {
        x = q.front() , q.pop();
        for(i = head[x] ; i ; i = next[i])
        {
            if(val[i] && !dis[to[i]])
            {
                dis[to[i]] = dis[x] + 1;
                if(to[i] == t) return 1;
                q.push(to[i]);
            }
        }
    }
    return 0;
}
int dinic(int x , int low)
{
    if(x == t) return low;
    int temp = low , i , k;
    for(i = head[x] ; i ; i = next[i])
    {
        if(val[i] && dis[to[i]] == dis[x] + 1)
        {
            k = dinic(to[i] , min(temp , val[i]));
            if(!k) dis[to[i]] = 0;
            val[i] -= k , val[i ^ 1] += k;
            if(!(temp -= k)) break;
        }
    }
    return low - temp;
}
int main()
{
    int n , m , i , j , ans = 0;
    scanf("%d%d" , &n , &m);
    s = 0 , t = n * m + 1;
    memset(map , 0x3f , sizeof(map));
    for(i = 1 ; i <= n ; i ++ )
        for(j = 1 ; j <= m ; j ++ )
            scanf("%d" , &map[i][j]) , num[i][j] = (i - 1) * m + j;
    for(i = 1 ; i <= n ; i ++ )
    {
        for(j = 1 ; j <= m ; j ++ )
        {
            if(map[i][j] == 2) add(s , num[i][j] , inf);
            if(map[i][j] == 1) add(num[i][j] , t , inf);
            else
            {
                if(map[i - 1][j] < 2) add(num[i][j] , num[i - 1][j] , 1);
                if(map[i][j - 1] < 2) add(num[i][j] , num[i][j - 1] , 1);
                if(map[i][j + 1] < 2) add(num[i][j] , num[i][j + 1] , 1);
                if(map[i + 1][j] < 2) add(num[i][j] , num[i + 1][j] , 1);
            }
        }
    }
    while(bfs()) ans += dinic(s , inf);
    printf("%d\n" , ans);
    return 0;
}

 

|转载请注明 [原文链接][作者] ,谢谢!

posted @ 2017-04-24 12:37  GXZlegend  阅读(242)  评论(0编辑  收藏  举报