• BZOJ1821: [JSOI2010]Group 部落划分 Group


    BZOJ1821: [JSOI2010]Group 部落划分 Group

    Description

    聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗。

    只是,这一切都成为谜团了——聪聪根本就不知道部落究竟是如何分布的。

    不过好消息是,聪聪得到了一份荒岛的地图。

    地图上标注了N个野人居住的地点(可以看作是平面上的坐标)。

    我们知道,同一个部落的野人总是生活在附近。

    我们把两个部落的距离,定义为部落中距离最近的那两个居住点的距离。

    聪聪还获得了一个有意义的信息——这些野人总共被分为了K个部落!

    这真是个好消息。聪聪希望从这些信息里挖掘出所有部落的详细信息。

    他正在尝试这样一种算法:

    对于任意一种部落划分的方法,都能够求出两个部落之间的距离,聪聪希望求出一种部落划分的方法,使靠得最近的两个部落尽可能远离。

    例如,下面的左图表示了一个好的划分,而右图则不是。

    请你编程帮助聪聪解决这个难题。

    Input

    第一行包含两个整数N和K(1< = N < = 1000,1< K < = N),分别代表了野人居住点的数量和部落的数量。
    接下来N行,每行包含两个正整数x,y,描述了一个居住点的坐标(0 < =x, y < =10000)

    Output

    输出一行,为最优划分时,最近的两个部落的距离,精确到小数点后两位。

    Sample Input

    4 2
    0 0
    0 1
    1 1
    1 0

    Sample Output

    1.00
    题解Here!

    本蒟蒻表示没有好的法子,直接 二分答案+并查集 水过。。。

    注意到这句话:靠得最近的两个部落尽可能远离。

    不就是二分嘛!

    二分最远距离的平方,并查集维护部落。

    还有,距离最好不要上来就开根号,不然会丢失精度的。

    注:图片上有彩蛋 JSOI 哦。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #define MAXN 1010
    #define eps (1e-6)
    using namespace std;
    int n,m,fa[MAXN];
    double l=0,r=0,mid;
    struct Point{
        double x,y;
    }a[MAXN];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline double dis(int i,int j){
        return ((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
    }
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    inline void uniun(int x,int y){x=find(x);y=find(y);if(x!=y)fa[y]=x;}
    int check(double x){
        int s=0;
        for(int i=1;i<=n;i++)fa[i]=i;
        for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
        if(dis(i,j)<=mid)uniun(j,i);
        for(int i=1;i<=n;i++)if(find(i)==i)s++;
        return s;
    }
    void work(){
        double ans;
        while(l<=r){
            mid=(l+r)/2.0;
            int s=check(mid);
            if(s==m)ans=mid;
            if(s>=m)l=mid+eps;
            else r=mid-eps;
        }
        printf("%.2lf
    ",sqrt(mid));
    }
    void init(){
        n=read();m=read();
        for(int i=1;i<=n;i++){
            a[i].x=read();a[i].y=read();
            for(int j=1;j<i;j++)r=max(r,dis(i,j));
        }
    }
    int main(){
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    javaScript 事件循环机制
    javaScript 原型与原型链
    清除浮动
    水平垂直居中的实现
    GitLab + Jenkins + Harbor 工具链快速落地指南
    a标签下载存储在项目中的文件
    判断数组对象中某一属性是否包含重复的值
    网站title前的小图标
    给二维数组动态赋值
    格式化eltable中的时间
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9405128.html
Copyright © 2020-2023  润新知