关闭

POJ 1838 Banana(并查集)

365人阅读 评论(0) 收藏 举报
分类:

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

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:390613次
    • 积分:20176
    • 等级:
    • 排名:第426名
    • 原创:1692篇
    • 转载:0篇
    • 译文:0篇
    • 评论:64条
    最新评论