首页 > 题解 > bzoj 1001 狼抓兔子

bzoj 1001 狼抓兔子

Description

现在小朋友们最喜欢的”喜羊羊与灰太狼”,话说灰太狼抓羊不到,但抓兔子还是比较在行的,
而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路
1:(x,y)<==>(x+1,y)
2:(x,y)<==>(x,y+1)
3:(x,y)<==>(x+1,y+1)
道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的狼的数量要最小。因为狼还要去找喜羊羊麻烦.

Input

第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值.
第二部分共N-1行,每行M个数,表示纵向道路的权值.
第三部分共N-1行,每行M-1个数,表示斜向道路的权值.
输入文件保证不超过10M

Output

输出一个整数,表示参与伏击的狼的最小数量.

Sample Input

3 4

5 6 4

4 3 1

7 5 3

5 6 7 8

8 7 6 5

5 5 5

6 6 6

Sample Output

14

题解

这题我竟然一直没做。

这个模型就是裸的最小割。发现是平面图,那为什么还要写网络流呢?

找出对偶图直接跑最短路就好了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> Pair;
const int N = 1010;
int n, m, a1[N][N], a2[N][N], a3[N][N];
struct edge {
    int to, next, val;
}e[N * N * 8];
int st[N * N * 2], tot;
void add_edge(int x, int y, int z) {
    e[++tot].next = st[x];
    e[tot].to = y, e[tot].val = z;
    st[x] = tot;
}
int dis[N * N * 2];
bool flag[N * N * 2];
int dijsktra(int start, int end) {
    memset(dis, 127, sizeof dis);
    memset(flag, 0, sizeof flag);
    dis[start] = 0;
    priority_queue< Pair, vector<Pair>, greater<Pair> >que;
    que.push(make_pair(dis[start], start));
    while (!que.empty()) {
        Pair now = que.top();
        que.pop();
        if (flag[now.second]) continue;
        flag[now.second] = 1;
        for (int i = st[now.second]; i; i = e[i].next)
            if (dis[now.second] + e[i].val < dis[e[i].to]) {
                dis[e[i].to] = dis[now.second] + e[i].val;
                if (!flag[e[i].to]) que.push(make_pair(dis[e[i].to], e[i].to));
            }
    }
    return dis[end];
}
void add(int x, int y, int z) {
//  printf("%d %d %d\n", x, y, z);
    add_edge(x, y, z), add_edge(y, x, z);
}
main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j < m; ++j)
            scanf("%d", &a1[i][j]);
    for (int i = 1; i < n; ++i)
        for (int j = 1; j <= m; ++j)
            scanf("%d", &a2[i][j]);
    for (int i = 1; i < n; ++i)
        for (int j = 1; j < m; ++j)
            scanf("%d", &a3[i][j]);
    m--, n--;
    int S = n * m * 2 + 1, T = S + 1;
    for (int i = 1; i <= m; ++i)
        add(i, S, a1[1][i]);
    for (int i = 1; i <= m; ++i)
        add(m * (2 * n - 1) + i, T, a1[n + 1][i]);
    for (int i = 1; i <= n; ++i)
        add(m * (2 * (i - 1) + 1), S, a2[i][m + 1]);
    for (int i = 1; i <= n; ++i)
        add(m * (2 * (i - 1) + 1) + 1, T, a2[i][1]);
//  puts("");
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            add(m * (2 * (i - 1)) + j, m * (2 * (i - 1) + 1) + j, a3[i][j]);
//  puts("");
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j < m; ++j)
            add(m * (2 * (i - 1)) + j, m * (2 * (i - 1) + 1) + j + 1, a2[i][j + 1]);
//  puts("");
    for (int i = 1; i < n; ++i)
        for (int j = 1; j <= m; ++j)
            add(m * (2 * (i - 1) + 1) + j, m * 2 * i + j, a1[i + 1][j]);
    printf("%d\n", dijsktra(S, T));
}