码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 1104 POI2007 洪水pow 并查集

时间:2015-03-10 17:17:34      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:bzoj   bzoj1104   并查集   

题目大意:给定一张地势图,所有的点都被水淹没,现在有一些关键点,要求放最少的水泵使所有关键点的水都被抽干

技术分享前排感谢VFK

首先可以证明一定存在一种最优解使所有的水泵都在关键点上

那么我们将所有关键点按照高度排序,从小到大枚举每个关键点

对于每个关键点x,我们将所有高度小于等于x点的点都加入并查集并将相邻的合并

由于x是并查集中最高的点,因此并查集中任意一个点放置水泵都会导致点x被抽干

故如果x所在并查集中已经放置过水泵,则无需在x点放置水泵

否则就要在x点放置一个水泵

时间复杂度O(mnlog(mn))

一开始写了个O(1000mn)的SPFA结果T到死- -

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1010
using namespace std;
struct abcd{
	int height,x,y;
	abcd() {}
	abcd(int _,int __,int ___):
		height(_),x(__),y(___) {}
	bool operator < (const abcd &a) const
	{
		return height < a.height;
	}
}cities[M*M],map[M*M];
int n,m,ans,tot;
int a[M][M];
namespace Union_Find_Set{
	pair<int,int> fa[M][M];
	bool pumped[M][M];
	pair<int,int> Find(pair<int,int> x)
	{
		if(fa[x.first][x.second]==make_pair(0,0)||fa[x.first][x.second]==x)
			return fa[x.first][x.second]=x;
		return fa[x.first][x.second]=Find(fa[x.first][x.second]);
	}
	void Union(pair<int,int> x,pair<int,int> y)
	{
		x=Find(x);y=Find(y);
		if(x==y) return ;
		fa[x.first][x.second]=y;
		pumped[y.first][y.second]|=pumped[x.first][x.second];
	}
}
void Insert(int x,int y)
{
	using namespace Union_Find_Set;
	static const int dx[]={1,-1,0,0};
	static const int dy[]={0,0,1,-1};
	int i;
	for(i=0;i<4;i++)
	{
		int xx=x+dx[i],yy=y+dy[i];
		if(xx<=0||yy<=0||xx>m||yy>n)
			continue;
		if(a[xx][yy]>a[x][y])
			continue;
		Union(make_pair(x,y),make_pair(xx,yy));
	}
}
int main()
{
	using namespace Union_Find_Set;
	int i,j;
	cin>>m>>n;
	for(i=1;i<=m;i++)
		for(j=1;j<=n;j++)
		{
			scanf("%d",&a[i][j]);
			if(a[i][j]>0)
				new (&cities[++tot])abcd(a[i][j],i,j);
			else
				a[i][j]=-a[i][j];
			new (&map[i*n-n+j])abcd(a[i][j],i,j);
		}
	sort(cities+1,cities+tot+1);
	sort(map+1,map+m*n+1);
	for(j=1,i=1;i<=tot;i++)
	{
		for(;j<=m*n&&map[j].height<=cities[i].height;j++)
			Insert(map[j].x,map[j].y);
		pair<int,int> temp=Find(make_pair(cities[i].x,cities[i].y));
		if(pumped[temp.first][temp.second])
			continue;
		++ans,pumped[temp.first][temp.second]=true;
	}
	cout<<ans<<endl;
	return 0;
}


BZOJ 1104 POI2007 洪水pow 并查集

标签:bzoj   bzoj1104   并查集   

原文地址:http://blog.csdn.net/popoqqq/article/details/44177149

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!