现在的位置: 首页 > 综合 > 正文

bzoj1001 狼抓兔子

2017年04月27日 ⁄ 综合 ⁄ 共 2622字 ⁄ 字号 评论关闭

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

这个题很简单噻,求对偶图然后单源最短路,,

我来讲一下,,平面图的最大流,就是最小割噻,,那么我们就是要找到一个割把该图割成两半,
分别包含源点汇点,,所以我们就是要找到一条从左下到右上的最短路,,
所以我们把每一个封闭区域当做一个点,两个区域的临边就是两点之间的距离,,
讲到这里七窍以通六窍,接下来的可以忽略。。。
然后求左下到右上的最短路噻~~我们可以以0为起点,把左下方的最外层的边与0相连,,右上方同理建一个终点,,
然后dijkstra+heap得解,,
AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;	
#define SIZE 3000000
#define inf 0x7fffffff
		struct node{
			int to,l,last;
		}edge[SIZE];
		bool operator<(const node &a,const node &b){
			return a.l > b.l;
		}
		int last[SIZE],top,ans,n,m,maxsize;
		int dist[SIZE];
		bool vis[SIZE];
		priority_queue<node> Q;
		int addline(int i,int j,int l){
			edge[++top].to = j;
			edge[top].l = l;
			edge[top].last = last[i];
			last[i] = top;
		}
		void PUSH(int to,int l){
			node x;
			x.to = to;
			x.l = l;
			Q.push(x);
		}
		int right_up(int i,int j){
			if ( i <= 1 || j >= m )
				return maxsize;
			if ( i > n || j < 1 )
				return 0; 
			return (n-1)*(m-1)+(i-2)*(m-1)+j;
		}
		int right_down(int i,int j){
			if ( i < 1 || j >= m )
				return maxsize;
			if ( i >= n || j < 1 )
				return 0;
			return (i-1)*(m-1)+j;
		}
		int heng(int i,int j,int l){
			int a = right_up(i,j);
			int b = right_down(i,j);
			addline(a,b,l);
			addline(b,a,l);
		}
		int shu(int i,int j,int l){
			int a = right_up(i+1,j);
			int b = right_down(i,j-1);
			addline(a,b,l);
			addline(b,a,l);
		}
		int xie(int i,int j,int l){
			int a = right_up(i+1,j);
			int b = right_down(i,j);
			addline(a,b,l);
			addline(b,a,l);
		}
		int dijkstra(){
//			Q.nul();
			for (int i = 0; i <= maxsize; i++){
				vis[i] = false;
				dist[i] = inf;
			}
			dist[0] = 0;
			PUSH(0,0);
			while(!Q.empty()){
				node x = Q.top(); Q.pop();
				int end = x.to;
				int dis = x.l;
//				printf("Get %d dist %d\n",end,dis);
				if ( vis[end] == true )
					continue;
				if ( end == maxsize )
					break;
				vis[end] = true;
				for (int wh = last[end];wh;wh = edge[wh].last){
					int to = edge[wh].to;
					if ( vis[to] == false && dist[to] > dist[end]+edge[wh].l ){
						dist[to] = dist[end] + edge[wh].l;
						PUSH(to,dist[to]);
					}
				}
			}
			ans = dist[maxsize];
			return ans;
		}
		void read(){
			scanf("%d%d",&n,&m);
			if ( n == 1 && m == 1 ){
//				printf("0");
				exit(0);
			}
			maxsize = 2*(n-1)*(m-1)+1;
			int l;
			for (int i = 1; i <= n; i++)
			for (int j = 1; j < m; j++){
				scanf("%d",&l);
				heng(i,j,l);
			}
			for (int i = 1; i < n; i++)
			for (int j = 1; j <= m; j++){
				scanf("%d",&l);
				shu(i,j,l);
			}
			for (int i = 1; i < n; i++)
			for (int j = 1; j < m; j++)
			{
				scanf("%d",&l);
				xie(i,j,l);
			}
		}
		int work(){
			return dijkstra();
		}
		void print(){
			printf("%d\n",ans);
		}
int main(){
	read();
	work();
	print();
	return 0;
}

抱歉!评论已关闭.