Peng Lv

毋意,毋必,毋固,毋我。 言必行,行必果。

导航

POJ 1838 Banana 并查集

 题意:有一只猴子喜欢吃香蕉,但他只能在相邻的两棵香蕉树之间行动,如果两棵树是在横方向或竖方向相邻的,那么这就组成一个区域,这个区域内猴子可以随意走动,有人可以把k个区域连接起来,从而使猴子在这k个区域内随意行动,问猴子最多可以在多少棵树内走动?给定n个树的坐标,和k。

 思路不难,使用并查集来对这n个点进行操作,最后选出前k个最大的根节点相加即可。在并查集中pre[]是一个节点的所有子结点的个数,是一个负值。

#include <iostream>
#include
<cstdio>
#include
<memory.h>
#include
<algorithm>
using namespace std;

#define MAXN 20000
struct Node{
int x,y;
int num;
}node[MAXN];
bool cmp(const Node& a, const Node& b)
{
if(a.x == b.x) return a.y<b.y;
return a.x<b.x;
}
bool cmp1(const Node& a,const Node& b)
{
if(a.y == b.y) return a.x<b.x;
return a.y < b.y;
}
bool cmp2(const int& a,const int& b)
{
return a<b;
}
int pre[MAXN];
int find_set( int x)
{
int root = x;
int tmp;
while(pre[root]>=0)
root
= pre[root];
while(x!=root)
{
tmp
= pre[x];
pre[x]
= root;
x
= tmp;
}
return root;
}
void union_set(const int& root1,const int& root2)
{
int a = pre[root1];
int b = pre[root2];
if(a > b)
{
pre[root1]
= root2;
pre[root2]
= a+b;
}
else
{
pre[root2]
= root1;
pre[root1]
= a+b;
}
}
int main()
{
int n,m,i,j,k;
int root1,root2;
while(scanf("%d%d",&n,&k)!=EOF)
{
memset(pre,
-1,sizeof(pre));
for(i = 0;i < n; ++i)
{
scanf(
"%d%d",&node[i].x,&node[i].y);
node[i].num
= i;
}
sort(node,node
+n,cmp);
for(i = 0;i < n-1; ++i)
if(node[i].x == node[i+1].x && node[i+1].y-node[i].y==1)
{
root1
= find_set(node[i].num);
root2
= find_set(node[i+1].num);
if(root1 != root2)
union_set(root1,root2);
}
sort(node,node
+n,cmp1);
for(i = 0;i < n-1; ++i)
if(node[i].y == node[i+1].y && node[i+1].x-node[i].x==1)
{
root1
= find_set(node[i].num);
root2
= find_set(node[i+1].num);
if(root1 != root2)
union_set(root1,root2);
}
sort(pre,pre
+n,cmp2);
int ans = 0;
for(i = 0; i < k;++i)
ans
-= pre[i];
printf(
"%d\n",ans);
}
return 0;
}

 

posted on 2010-03-09 18:14  Lvpengms  阅读(534)  评论(0编辑  收藏  举报