洛谷 - 部落划分

原题:[P4047 JSOI2010]部落划分 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题意:把n个地点划分成k个部分,给出每个点的坐标,要使每个部分之间的最短距离(两个部分中距离最近的两个地点的距离)尽量大。

分析:题意可以转化为,使一个部分间地点的距离尽量小,那么剩下的边,也就是部分间的距离自然就最大了,所以可以用kruskal。将边权从小到大排序,分前m-s+1条边权,前m-s条是各部分间地点的距离,最后1个是部分间的最短距离,即答案。

题解:

#include <bits/stdc++.h>
using namespace std;
const int N=1e3+5,M=N*N;
int fa[N],n,k,x[N],y[N],cnt;
double ans=0;
struct node
{
    int x,y;
    double z;
}edge[M];
bool cmp(node a,node b)
{
    if(a.z==b.z) return a.x<b.x;
    return a.z<b.z;
}
double cal(int x1,int y1,int x2,int y2)
{
    return (double)sqrt((double)(x1-x2)*(x1-x2)+(double)(y1-y2)*(y1-y2));
}
int find(int x)
{
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}
void kruskal()
{
    for(int i=1;i<=n;i++) fa[i]=i;

    int sum=0;
    for(int i=1;i<=cnt;i++)
    {
        int u=edge[i].x,v=edge[i].y;
        u=find(u),v=find(v);

        if(u!=v)
        {
            fa[u]=v;
            sum++;
            ans=max(ans,edge[i].z);
        }

        if(n-k+1==sum)
        {
            break;
        }
    }
}

int main()
{
    scanf("%d %d",&n,&k);

    for(int i=1;i<=n;i++)
    {
        cin>>x[i]>>y[i];
    }

    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            edge[++cnt].x=i,edge[cnt].y=j;
            edge[cnt].z=cal(x[i],y[i],x[j],y[j]);

        }
    }

    sort(edge+1,edge+1+cnt,cmp);

    kruskal();

    printf("%.2lf",ans);

    return 0;
}
posted @ 2021-08-15 22:59  AtomsH  阅读(56)  评论(0)    收藏  举报