BZOJ 1001: [BeiJing2006]狼抓兔子

題目地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1001


題目大意:見原題&算法討論。


算法討論:

        很容易看出這是最小割。

        我們首先想到的是最小割=最大流。

        但是點數最多有1e6,用O(n^2*m)的Dinic和O(n*m^2)的sap顯然都是要超時的。(據說Dinic也能過?)

        於是我們想到了另一個公式:平面圖最大流=對偶圖最短路。

        網格圖做對偶圖是很方便的啦~

        然後SPFA就更方便了啦~


Code:

/*
 * Problem:1001
 * Author:PYC
 */

#include <cstdio>

#define Vnum (1000*1000*2)
#define Enum (1000*1000*5*2)
#define maxn 2000100
#define oo (1<<30)
#define Bnum 1100
#define ooo 2147483647 

using namespace std;

int n,m,mm,son[Vnum],next[Enum],ed[Enum],data[Enum],end,h=0,t=1,q[maxn],dis[maxn],tt=1,id[Bnum][Bnum][2];
bool v[maxn];

inline int min(int x,int y){
	return x<y?x:y;
}

inline void INSERT(int x,int y,int z){
	mm++;
	next[mm]=son[x];
	son[x]=mm;
	ed[mm]=y;
	data[mm]=z;
}

inline void insert(int x,int y,int z){
	INSERT(x,y,z);
	INSERT(y,x,z);
}

void spfa(){
	for (int i=2;i<=end;++i) dis[i]=oo;
	v[1]=1;
	q[1]=1;
	while (h!=t){
		h++;
		h%=maxn;
		v[q[h]]=0;
		int x=q[h];
		for (int i=son[x];i;i=next[i]){
			int y=ed[i];
			if (dis[x]+data[i]<dis[y]){
				dis[y]=dis[x]+data[i];
				if (!v[y]){
					t++;
					t%=maxn;
					v[y]=1;
					q[t]=y;
				}
			}
		}
	}
}

int main(){
	scanf("%d%d",&n,&m);
	if (n==1 && m==1){
		printf("0\n");
		return 0;
	}
	if (n==1){
		int ans=ooo;
		for (int i=1;i<=m-1;++i){
			int x;
			scanf("%d",&x);
			ans=min(ans,x);
		}
		printf("%d\n",ans);
		return 0;
	}
	if (m==1){
		int ans=ooo;
		for (int i=1;i<=n-1;++i){
			int x;
			scanf("%d",&x);
			ans=min(ans,x);
		}
		printf("%d\n",ans);
		return 0;
	}
	for (int i=1;i<=n-1;++i)
		for (int j=1;j<=m-1;++j){
			++tt;
			id[i][j][0]=tt;
			++tt;
			id[i][j][1]=tt;
		}
	end=tt+1;
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m-1;++j){
			int x;
			scanf("%d",&x);
			if (i==1){
				insert(1,id[i][j][0],x);
				continue;
			}
			if (i==n){
				insert(end,id[i-1][j][1],x);
				continue;
			}
			insert(id[i][j][0],id[i-1][j][1],x);
		}
	for (int i=1;i<=n-1;++i)
		for (int j=1;j<=m;++j){
			int x;
			scanf("%d",&x);
			if (j==1){
				insert(end,id[i][j][1],x);
				continue;
			}
			if (j==m){
				insert(1,id[i][j-1][0],x);
				continue;
			}
			insert(id[i][j-1][0],id[i][j][1],x);
		}
	for (int i=1;i<=n-1;++i)
		for (int j=1;j<=m-1;++j){
			int x;
			scanf("%d",&x);
			insert(id[i][j][0],id[i][j][1],x);
		}
	spfa();
	printf("%d\n",dis[end]);
	return 0;
}

By Charlie Pan

Mar 15,2014

發佈了52 篇原創文章 · 獲贊 2 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章