[Luogu P2598] [BZOJ 1412] [ZJOI2009]狼和羊的故事

洛谷传送门
BZOJ传送门

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

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

说明

数据范围

10%的数据 n , m ≤ 3 n,m≤3 nm3

30%的数据 n , m ≤ 20 n,m≤20 nm20

100%的数据 n , m ≤ 100 n,m≤100 nm100

解题分析

把空地也看成羊, 然后羊、空地和空地、狼连边, S向羊连边, 狼向T连边,跑最小割就好。

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <queue>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define S 0
#define MX 10050
#define INF 1e8
#define get(i, j) ((i - 1) * m + j)
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    for (; !isdigit(c); c = gc);
    for (;  isdigit(c); c = gc)
    x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int n, m, cnt, T, ans;
int mp[105][105], head[MX], cpy[MX], layer[MX];
struct Edge {int to, fl, nex;} edge[MX << 3];
IN void add(R int from, R int to, R int fl)
{
    edge[++cnt] = {to, fl, head[from]}, head[from] = cnt;
    edge[++cnt] = {from, 0, head[to]}, head[to] = cnt;
}
namespace Dinic
{
    std::queue <int> q;
    IN bool BFS()
    {
        std::memset(layer, 0, sizeof(layer));
        layer[S] = 1; R int now; q.push(S);
        W (!q.empty())
        {
            now = q.front(); q.pop();
            for (R int i = head[now]; ~i; i = edge[i].nex)
            {
                if ((!layer[edge[i].to]) && edge[i].fl)
                layer[edge[i].to] = layer[now] + 1, q.push(edge[i].to);
            }
        }
        return layer[T];
    }
    int DFS(R int now, R int avai)
    {
        if (now == T) return avai;
        R int lef = avai, buf;
        for (R int i = head[now]; ~i; i = edge[i].nex)
        {
            if (layer[edge[i].to] == layer[now] + 1 && edge[i].fl)
            {
                buf = DFS(edge[i].to, min(edge[i].fl, lef));
                if (!buf) continue;
                lef -= buf, edge[i].fl -= buf, edge[i ^ 1].fl += buf;
                if (!lef) return avai;
            }
        }
        return avai - lef;
    }
    void init()
    {
        W (BFS()) ans += DFS(S, INF);
        printf("%d", ans);
    }
}
int main(void)
{
    std::memset(head, cnt = -1, sizeof(head));
    int foo;
    in(n), in(m);
    for (R int i = 1; i <= n; ++i)
    for (R int j = 1; j <= m; ++j)
    in(mp[i][j]);
    T = n * m + 1;
    for (R int i = 1; i <= n; ++i)
    {
        for (R int j = 1; j <= m; ++j)
        {
            foo = get(i, j);
            if (mp[i][j] == 1)
            {
                add(S, foo, INF);
                if (i > 1) if (mp[i - 1][j] ^ 1) add(foo, get(i - 1, j), 1);
                if (i < n) if (mp[i + 1][j] ^ 1) add(foo, get(i + 1, j), 1);
                if (j > 1) if (mp[i][j - 1] ^ 1) add(foo, get(i, j - 1), 1);
                if (j < m) if (mp[i][j + 1] ^ 1) add(foo, get(i, j + 1), 1);
            }
            else if(mp[i][j] == 0)
            {
                if (i > 1) if (mp[i - 1][j] ^ 1) add(foo, get(i - 1, j), 1);
                if (i < n) if (mp[i + 1][j] ^ 1) add(foo, get(i + 1, j), 1);
                if (j > 1) if (mp[i][j - 1] ^ 1) add(foo, get(i, j - 1), 1);
                if (j < m) if (mp[i][j + 1] ^ 1) add(foo, get(i, j + 1), 1);
            }
            else add(foo, T, INF);
        }
    }
    Dinic::init();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值