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));
}