洛谷 P4047 部落划分【最小生成树】

洛谷 P4047 部落划分

先处理出所有可以连的边,n个点理论上最多可以连n*(n-1)/2条边,现在要划分为k个部落(k个连通分支),找规律,可以得到需要连的边的数量为n-k。为了使靠得最近的两个部落尽可能远离,先连权值小的边,连到n-k条边时就已经完成了划分,如果再连一条边即第n-k+1条边,就是靠得最近的两个部落的最大距离。

通过以上分析不难得出,本题本质就是最小生成树的模板题,并不难。
(可能因为“靠得最近的两个部落尽可能远离”这句话说得比较绕…)

#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n,k,cnt,num,pre[N];
struct node
{
    double x,y;
}p[N];
struct edge
{
    int a,b;
    double val;//边的长度(权值)
}e[N*N];
int find(int x)
{
    if(x!=pre[x])pre[x]=find(pre[x]);
    return pre[x];
}
void join(int a,int b)
{pre[find(a)]=find(b);}
bool cmp(edge s1,edge s2)
{return s1.val<s2.val;}//注意是小于号
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>p[i].x>>p[i].y;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            e[++cnt].a=i;
            e[cnt].b=j;
            e[cnt].val=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
        }
    sort(e+1,e+cnt+1,cmp);
    for(int i=1;i<=n;i++)//一定要记得初始化!
        pre[i]=i;
    for(int i=1;i<=cnt;i++)
    {
        if(find(e[i].a)!=find(e[i].b))
        {
            join(e[i].a,e[i].b);
            num++;
            if(num==n-k+1){printf("%.2lf\n",e[i].val);break;}
        }
    }
    return 0;
}
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页