bzoj1001:[BeiJing2006]狼抓兔子
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
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
HINT
2015.4.16新加数据一组,可能会卡掉从前可以过的程序。
Source
题解:
考虑平面图最小割转对偶图最短路,这两个转换完就是完全一样的东西,包括数量,然后你就可以写什么最小割计数了,但是这题只要求最短路。
那你跑一遍spfa就好了。
代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include <iostream> int n, m, s, t; struct edge { int to, val; edge *next; } e[8000010], *et = e, *last[1000010]; void add(int u, int v, int w) { //printf("edge : %d -> %d : %d\n", u, v, w); *++et = (edge) {v, w, last[u]}, last[u] = et; *++et = (edge) {u, w, last[v]}, last[v] = et; } int vis[2000010], dis[2000010]; int main() { scanf("%d%d", &n, &m); s = (n-1)*(m-1)*2+1, t = s+1; for(int i = 1; i <= n; i++) for(int j = 1; j < m; j++) { int v; scanf("%d", &v); if(i == 1) add(s, (i-1)*(m-1)*2+j*2, v); else if(i == n) add((i-2)*(m-1)*2+j*2-1, t, v); else add((i-2)*(m-1)*2+j*2-1, (i-1)*(m-1)*2+j*2, v); } for(int i = 1; i < n; i++) for(int j = 1; j <= m; j++) { int v; scanf("%d", &v); if(j == 1) add((i-1)*(m-1)*2+j*2-1, t, v); else if(j == m) add(s, (i-1)*(m-1)*2+j*2-2, v); else add((i-1)*(m-1)*2+j*2-2, (i-1)*(m-1)*2+j*2-1, v); } for(int i = 1; i < n; i++) for(int j = 1; j < m; j++) { int v; scanf("%d", &v); add((i-1)*(m-1)*2+j*2-1, (i-1)*(m-1)*2+j*2, v); } static int q[2000010]; int l = 0, r = 0; memset(dis, 63, sizeof dis); vis[q[r++] = s] = 1; dis[s] = 0; while(l < r) { int u = q[l++]; if(l >= n*m*2) l -= n*m*2; for(edge *it = last[u]; it; it = it->next) if(dis[u]+(it->val) < dis[it->to]) { dis[it->to] = dis[u]+(it->val); if(!vis[it->to]) { vis[it->to] = 1, q[r++] = it->to; if(r >= n*m*2) r -= n*m*2; } } vis[u] = 0; } printf("%d\n", dis[t]); }