POJ 1838 Banana(并查集)

原创 2015年07月07日 10:53:08

Description
一个点用坐标(x,y)表示,如果两个点在水平方向或垂直方向上相邻,则两个点属于一个区域,即点1(x1,y1),点2(x2,y2)相邻当且仅当x1==x2,|y1-y2|=1或者|x1-x2|=1,y1=y2。给定一些点,相邻的点构成一个区域,求出k个区域所能拥有的最大点数(k不大于区域数)
Input
第一行两个整数n和k分别代表点数和区域数,之后n行为n个点的坐标
Output
输出k个区域所能拥有的最大点数
Sample Input
10 3
7 10
1 1
101 1
2 2
102 1
7 11
200 202
2 1
3 2
103 1
Sample Output
9
Solution
可用并查集解决,一个区域表示为一个并查集,两个区域相邻时,合并这两个并查集。同时记录并查集中的点数目。
初始时,每个点为一个并查集。对x坐标相同、y坐标相差为1的点,合并它们所在的并查集,合并时需要判断两个点是否位于同一个集合。合并时需要先找到各自集合的根节点,然后让其中一个根节点指向另一个根节点完成合并。对y坐标相同、x坐标相差为1的点,合并它们所在的并查集。
当所有相邻点进行了合并操作之后,对并查集点数目从大到小排序,取前K个值的总和作为结果输出。
Code

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF (1<<29)
#define maxn 16005
struct node
{
    int x,y,flag;//x,y记录点坐标,flag记录点的下标便于操作 
}pos[maxn];
int par[maxn];
int rank[maxn];
int mem[maxn];
int ans[maxn];
int n,k,num;
void init(int n)
{
    for(int i=0;i<n;i++)
    {
        par[i]=i;
        rank[i]=0;
        mem[i]=1;
        pos[i].flag=i;
    }
}
int find(int x)
{
    if(par[x]==x)
        return x;
    return par[x]=find(par[x]);
}
void unite(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y)
        return ;
    if(rank[x]<rank[y])
    {
        par[x]=y;
        mem[y]+=mem[x];//合并区域点数相加 
    }
    else
    {
        par[y]=x;
        mem[x]+=mem[y];//合并区域点数相加 
        if(rank[x]==rank[y])
            rank[x]++;
    }
}
int cmp_x(node a,node b)
{
    if(a.x==b.x)
        return a.y<b.y;
    return a.x<b.x;
}
int cmp_y(node a,node b)
{
    if(a.y==b.y)
        return a.x<b.x;
    return a.y<b.y;
}
int cmp(int x,int y)
{
    return x>y;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++)
        scanf("%d%d",&pos[i].x,&pos[i].y);
    init(n);
    sort(pos,pos+n,cmp_x);//对点按横坐标升序排 
    for(int i=0;i<n-1;i++)//对x坐标相同、y坐标相差为1的点,合并它们所在的并查集
        if(pos[i].x==pos[i+1].x&&pos[i+1].y-pos[i].y==1)
            unite(pos[i].flag,pos[i+1].flag);
    sort(pos,pos+n,cmp_y);//对点按纵坐标升序排 
    for(int i=0;i<n-1;i++)//对y坐标相同、x坐标相差为1的点,合并它们所在的并查集 
        if(pos[i].y==pos[i+1].y&&pos[i+1].x-pos[i].x==1)
            unite(pos[i].flag,pos[i+1].flag);
    int res=0;
    for(int i=0;i<n;i++)//找到每个区域的根节点,记录该区域的点数 
        if(par[i]==i)
            ans[res++]=mem[i];
    sort(ans,ans+res,cmp);//对每个区域点数按降序排 
    for(int i=0;i<k;i++)//取前k个区域即为最大值 
        num+=ans[i];
    printf("%d\n",num);
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

POJ 1838 Banana(并查集)

题目: 一个点用坐标(x,y)表示,如果两个点在水平方向或垂直方向上相邻,则两个点属于一个区域,即点1(x1,y1),点2(x2,y2)相邻当且仅当x1==x2,|y1-y2|=1或者|x1-x2|...

POJ1838 Bananas 并查集

1.题目描述: Banana Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 236...

【poj1838】Bananas——并查集

Banana Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 2220   Accepte...
  • CFhM_R
  • CFhM_R
  • 2016年02月25日 00:04
  • 154

poj1838 并查集 抽象模型

题意: 一个点用坐标(x,y)表示,如果两个点在水平方向或垂直方向上相邻,则两个点属于一个区域, 即点1(x1,y1),点2(x2,y2)相邻当且仅当x1==x2,|y1-y2|=1或者|x1-x...

并查集 Poj 1838 + 1611 + 1962 + Zoj 2833

Poj 1838 这个题可能用搜索更好,但既然是在练习并查集…… #include #include #include #include using namespace std; s...

POJ 1988 简单并查集,

  • 2011年03月18日 18:00
  • 2KB
  • 下载

并查集代码

  • 2015年12月12日 20:18
  • 1KB
  • 下载

POJ2513-Colored Sticks(并查集 欧拉回路)

标题目大意 给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的。 分析我们以一个节点表示一种颜色,将每个木棍两端的颜色连上边。这样原问题...
  • mmy1996
  • mmy1996
  • 2016年09月06日 21:38
  • 130

ACM并查集讲解的深化和扩展

  • 2016年07月01日 17:27
  • 1.58MB
  • 下载

并查集初步(黄劲松).ppt

  • 2015年04月01日 15:45
  • 424KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:POJ 1838 Banana(并查集)
举报原因:
原因补充:

(最多只允许输入30个字)