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 ;
}

 

你可能感兴趣的:(poj)