题339.最小生成树扩展-acwing-Q1145--北极通讯网络


题339.最小生成树扩展-acwing-Q1145–北极通讯网络


一、题目

在这里插入图片描述
在这里插入图片描述

二、题解

本题给定k个卫星要你利用这些无视距离的卫星通信去去掉将所有点连通所形成的最小生成树里的较大的边,从而使得剩下的连通块中的最大边的权值最小(而不是单纯去掉最小生成树中的k-1条较大边,因为它是给点成边,受限制),输出这个结果。
由于最小生成树Kruskal算法利用了并查集,每次做并操作可让连通块个数少1,所以显然依据前面的分析,当连通块个数减少到k(这k个连通块可用k-1条卫星通信边连接)时,之前所选的边的权值即为答案。代码如下:

#include <bits/stdc++.h>

#define x first
#define y second

using namespace std;

typedef pair<int,int> pii;
const int maxn=550;

struct Edge
{
    int u,v;
    double w;
    bool operator < (const Edge &e) const
    {
        return w<e.w;
    }
};

int n,k;
pii p[maxn];
vector<Edge> e;
double res;
int fa[maxn];

double getD(pii p1,pii p2)//求两点间距离,这里为边权
{
    int dx=p1.x-p2.x,dy=p1.y-p2.y;
    return sqrt(dx*dx+dy*dy);
}

int findRoot(int v)//找根
{
    if(fa[v]<0)
    {
        return v;
    }
    else
    {
        return fa[v]=findRoot(fa[v]);
    }
}

void unionSet(int v1,int v2)//并集
{
    int root1=findRoot(v1),root2=findRoot(v2);
    if(root1==root2)
    {
        return;
    }
    if(fa[root1]<fa[root2])
    {
        fa[root1]+=fa[root2];
        fa[root2]=root1;
    }
    else
    {
        fa[root2]+=fa[root1];
        fa[root1]=root2;
    }
    return;
}

void Kruskal()
{
    memset(fa,-1,sizeof fa);
    int cnt=n;//连通块个数
    for(int i=0;i<e.size();i++)
    {
        if(cnt==k)//当连通块个数恰好可以等于k,即这些连通块可用k个卫星进行通信,则退出循环
        {
            break;
        }
        int u=e[i].u,v=e[i].v;
        double w=e[i].w;
        int root1=findRoot(u),root2=findRoot(v);
        if(root1!=root2)
        {
            unionSet(u,v);
            cnt--;//每做一次并集操作,连通块个数-1
            res=w;//更新答案,当连通块个数恰好为k时,选入的那条件的权值即为当前最大,总体最大最小,即d值
        }
    }
}

int main()
{
    cin>>n>>k;
    for(int i=0;i<n;i++)
    {
        cin>>p[i].x>>p[i].y;
    }
    for(int i=0;i<n;i++)//连边
    {
        for(int j=i+1;j<n;j++)
        {
            e.push_back({i,j,getD(p[i],p[j])});
        }
    }
    sort(e.begin(),e.end());
    Kruskal();
    printf("%.2f",res);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值