【BZOJ1001】[BeiJing2006]狼抓兔子 对偶图最短路

【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

题解:由于n太大所以不能用最小割,本题正解为对偶图最短路

先yy一下,如果有一个最优方案,那么它一定是一条线,把矩形切成两个块,要求这条线上每个点的3条入边都要埋伏,这不是最短路吗?

建图:

将每个三角形看成点,矩形的右、上两条边为起点,左、下两条边为终点,每一个三角形的边都相当于将两个三角形连起来的线(注意是无向边)

然后跑对优化Dijkstra

注意n==1||m==1的情况,数组要开大点

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <utility>
#define Up(A,B)	((A-1)*m+B)
#define Down(A,B) ((A-1)*m+B+n*m)
using namespace std;
int n,m,cnt,S,T;
int to[6000010],next[6000010],val[6000010],head[2000010],dis[2000010],vis[2000010];
priority_queue<pair<int,int> > pq;
int readin()
{
	int ret=0;	char gc=getchar();
	while(gc<'0'||gc>'9')	gc=getchar();
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret;
}
void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
	to[cnt]=a,val[cnt]=c,next[cnt]=head[b],head[b]=cnt++;
}
int main()
{
	n=readin()-1,m=readin()-1;
	memset(head,-1,sizeof(head));
	S=0,T=2*n*m+1;
	int i,j,u,a,b;
	for(i=1;i<=n+1;i++)
	{
		for(j=1;j<=m;j++)
		{
			a=Down(i-1,j),b=Up(i,j);
			if(i==1)	a=S;
			if(i==n+1)	b=T;
			add(a,b,readin());
		}
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m+1;j++)
		{
			a=Down(i,j),b=Up(i,j-1);
			if(j==1)	b=T;
			if(j==m+1)	a=S;
			add(a,b,readin());
		}
	}
	for(i=1;i<=n;i++)	for(j=1;j<=m;j++)	add(Up(i,j),Down(i,j),readin());
	memset(dis,0x3f,sizeof(dis));
	pq.push(make_pair(0,S)),dis[S]=0;
	while(!pq.empty())
	{
		u=pq.top().second,pq.pop();
		if(vis[u])	continue;
		vis[u]=1;
		for(i=head[u];i!=-1;i=next[i])
		{
			if(dis[to[i]]>dis[u]+val[i])
			{
				dis[to[i]]=dis[u]+val[i];
				pq.push(make_pair(-dis[to[i]],to[i]));
			}
		}
	}
	printf("%d",dis[T]);
	return 0;
}
原文地址:https://www.cnblogs.com/CQzhangyu/p/6525361.html