BZOJ1412 / ZJOI2009 狼和羊的故事【网络流/最小割】

来源:互联网 发布:c语言解惑 编辑:程序博客网 时间:2024/05/17 20:30

Description

Orez试图羊狼合养! Orez的羊狼圈可以看作一个nm个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼总是对羊垂涎三尺。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。

Input

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

Output

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

Solution

这题要把狼羊分开,即是求一个最小割。割什么呢?就是需要建篱笆隔开的两块地。显然同种生物之间建篱笆纯属浪费,于是建边:
000102
1012
2021
由于割掉一条边相当于建一个篱笆,因此容量是1

最小割即为最大流,建虚拟源汇ST,要把12隔开,只需要建边:
S12Tc=inf
容量无限因为这些边不能割。

跑完最大流,即为最小割。

代码:

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>using namespace std;const int maxn = 50088;const int INF = (int)1e9;const int inf = (int)1e5;int edge_num = 1, m, n, S, T;int hed[maxn], dep[maxn];struct Edge {    int from, to, nxt, c;} edge[maxn * 4];void addedge(int from, int to, int c){    edge[++edge_num].nxt = hed[from];    edge[edge_num].from = from;    edge[edge_num].to = to;    hed[from] = edge_num;    edge[edge_num].c = c;}void adde(int from, int to, int c){    addedge(from, to, c);    addedge(to, from, 0);}int queue[maxn], head = 0, tail = 0;bool bfs(){    queue[head] = S;    head = tail = 0;    memset(dep, 0, sizeof(dep));    dep[S] = 1;    while (head <= tail){        int cur = queue[head]; head++;        for (int i = hed[cur]; i; i = edge[i].nxt){            int to = edge[i].to;            if (!dep[to] && edge[i].c) {                dep[to] = dep[cur] + 1;                queue[++tail] = to;            }        }    }    return dep[T];}int dfs(int x, int flow){    if (x == T) return flow;    int ret = 0;    for (int i = hed[x]; i; i = edge[i].nxt){        int to = edge[i].to;        if (dep[to] == dep[x] + 1 && edge[i].c){            int tmp = dfs(to, min(flow, edge[i].c));            edge[i].c -= tmp;            edge[i ^ 1].c += tmp;            flow -= tmp;            ret += tmp;        }    }    if (!ret) dep[x] = 0;    return ret;}int dinic(){    int ret = 0;    while (bfs()){        ret += dfs(S, INF);    }    return ret;}inline int hash(int i, int j){    return (i - 1) * m + j;}int a[maxn];void link(int i, int j, int x, int y){    if (x <= 0 || y <= 0 || x > n || y > m) return;    if (a[hash(i, j)] && a[hash(i, j)] == a[hash(x, y)]) return;    adde(hash(i, j), hash(x, y), 1);}int main(){    scanf("%d%d", &n, &m);    for (int i = 1; i <= n; i++)        for (int j = 1; j <= m; j++)            scanf("%d", &a[hash(i, j)]);    S = 0; T = m * n + 1;    for (int i = 1; i <= n; i++)        for (int j = 1; j <= m; j++){            if (a[hash(i, j)] == 1) adde(S, hash(i, j), INF);            if (a[hash(i, j)] == 2) adde(hash(i, j), T, INF);            link(i, j, i - 1, j);            link(i, j, i, j - 1);            link(i, j, i + 1, j);            link(i, j, i, j + 1);        }    printf("%d\n", dinic());    return 0;}
原创粉丝点击