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

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

  

posted @ 2017-11-23 09:04  wazwaztime  阅读(171)  评论(0编辑  收藏  举报