Kruskal - Arctic Network - POJ 2349

Kruskal - Arctic Network - POJ 2349

题目:

n 个 村 庄 ( x , y ) , 要 在 两 两 间 建 立 通 讯 。 n个村庄(x,y),要在两两间建立通讯。 n(x,y)

无 限 电 收 发 机 的 参 数 为 d , 可 以 覆 盖 直 线 距 离 在 d 以 内 的 村 庄 。 无限电收发机的参数为d,可以覆盖直线距离在d以内的村庄。 d线d

卫 星 设 备 可 以 覆 盖 任 意 距 离 的 村 庄 。 卫星设备可以覆盖任意距离的村庄。

有 k 台 卫 星 设 备 , 无 限 电 收 发 机 数 量 不 限 。 有k台卫星设备,无限电收发机数量不限。 k

要 覆 盖 n 个 村 庄 , 问 如 何 分 配 k 台 卫 星 设 备 , 使 得 使 用 的 无 限 电 收 发 机 的 参 数 d 尽 量 小 , 输 出 最 小 的 参 数 d 。 要覆盖n个村庄,问如何分配k台卫星设备,使得使用的无限电收发机的参数d尽量小,输出最小的参数d。 nk使使dd

抽象出题意:

给 定 一 个 n 个 点 的 图 , 两 点 之 间 相 连 通 需 要 一 定 的 花 费 。 给定一个n个点的图,两点之间相连通需要一定的花费。 n

可 从 中 选 择 k 个 点 , 这 k 个 点 无 需 花 费 任 何 代 价 即 可 连 通 。 可从中选择k个点,这k个点无需花费任何代价即可连通。 kk

问 最 少 需 要 多 少 代 价 使 得 整 个 图 连 通 。 问最少需要多少代价使得整个图连通。 使

两 点 之 间 连 通 的 代 价 为 两 点 间 的 欧 几 里 得 距 离 。 两点之间连通的代价为两点间的欧几里得距离。

全 图 的 代 价 为 边 权 的 最 大 值 。 全图的代价为边权的最大值。

输入:

首 行 输 入 整 数 T , 共 有 T 组 测 试 数 据 。 首行输入整数T,共有T组测试数据。 TT

每 组 数 据 首 行 包 括 整 数 k 和 n 。 每组数据首行包括整数k和n。 kn

接 着 输 入 n 行 , 表 示 n 个 点 的 坐 标 。 接着输入n行,表示n个点的坐标。 nn

输出:

一 个 整 数 , 表 示 最 小 花 费 。 一个整数,表示最小花费。

Sample Input

1
2 4
0 100
0 300
0 600
150 750

Sample Output

212.13

数据范围:

1 ≤ k ≤ 100 , k < n ≤ 500 , 0 ≤ x , y ≤ 10000 1≤k≤100,k<n≤500,0≤x,y≤10000 1k100k<n5000x,y10000


分析:

我 们 的 首 要 任 务 是 使 得 n 个 点 连 通 , 在 这 个 前 提 下 , 要 使 得 所 有 边 的 边 权 最 大 值 最 小 。 我们的首要任务是使得n个点连通,在这个前提下,要使得所有边的边权最大值最小。 使n使

采 用 k r u s k a l 算 法 , 每 次 添 加 一 条 边 必 然 使 得 图 中 的 连 通 块 数 量 减 少 1 。 采用kruskal算法,每次添加一条边必然使得图中的连通块数量减少1。 kruskal使1

通 过 k r u s k a l 算 法 , 优 先 考 虑 边 权 小 的 边 , 直 到 连 通 块 的 数 量 减 少 到 k 个 , 通过kruskal算法,优先考虑边权小的边,直到连通块的数量减少到k个, kruskalk

最 后 对 k 个 连 通 块 , 每 个 连 通 块 中 放 一 个 卫 星 设 备 , 就 能 够 使 得 全 图 连 通 。 最后对k个连通块,每个连通块中放一个卫星设备,就能够使得全图连通。 k使

由 于 边 权 是 从 小 到 大 排 序 的 , 最 后 添 加 的 一 条 边 就 是 整 个 图 中 最 长 的 边 , 即 所 求 最 小 的 参 数 d 。 由于边权是从小到大排序的,最后添加的一条边就是整个图中最长的边,即所求最小的参数d。 d

说明:

在 k r u s k a l 算 法 执 行 的 过 程 中 : 在kruskal算法执行的过程中: kruskal

若 从 小 到 大 依 次 添 加 了 前 n − k 小 的 边 , 形 成 一 整 个 连 通 块 和 k 个 孤 立 的 单 点 , 此 时 必 是 最 优 解 。 若从小到大依次添加了前n-k小的边,形成一整个连通块和k个孤立的单点,此时必是最优解。 nkk

若 在 考 虑 某 条 较 小 边 时 生 成 了 环 , 如 果 选 了 这 条 边 , 对 整 个 图 的 连 通 性 无 影 响 , 所 以 不 选 , 放 卫 星 , 是 最 优 解 。 若在考虑某条较小边时生成了环,如果选了这条边,对整个图的连通性无影响,所以不选,放卫星,是最优解。

所 以 k r u s k a l 是 正 确 的 。 所以kruskal是正确的。 kruskal

注意:

O J 上 选 择 G + + 与 C + + 提 交 的 注 意 点 : OJ上选择G++与C++提交的注意点: OJG++C++
在这里插入图片描述
参考:G++与C++的区别

另 外 , 本 题 是 多 组 数 据 , 并 查 集 在 使 用 时 , 点 的 编 号 是 从 0 开 始 的 , 所 以 要 初 始 化 p [ 0 ] = 0 。 另外,本题是多组数据,并查集在使用时,点的编号是从0开始的,所以要初始化p[0]=0。 使0p[0]=0

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>

#define P pair<int,int>
#define x first
#define y second

using namespace std;

const int N=510, M=N*N;

int n,m,k,T;
int p[N];
P V[N];
double res;

struct edge
{
    int u,v;
    double w;
    bool operator < (const edge &t) const
    {
        return w<t.w;
    }
}E[M];

int Find(int x)
{
    if(p[x]!=x) return p[x]=Find(p[x]);
    return p[x];
}

double get_dist(P a,P b)
{
    double dx=a.x-b.x,dy=a.y-b.y;
    return sqrt(dx*dx+dy*dy);
}

void kruskal()
{
    sort(E,E+m);
    
    int cnt=n;
    for(int i=0;i<m;i++)    //n-k
    {
        if(cnt<=k) break;
        
        int a=Find(E[i].u),b=Find(E[i].v);
        if(a!=b)
        {
            p[a]=b;
            res=E[i].w;
            cnt--;
        }
    }
}

int main()
{
    cin>>T;
    while(T--)
    {
        m=0;
        cin>>k>>n;
        for(int i=0;i<=n;i++) p[i]=i;	//下面坐标从0开始,所以p[0]也要初始化!
        for(int i=0;i<n;i++) cin>>V[i].x>>V[i].y;
        
        for(int i=0;i<n;i++)
            for(int j=0;j<i;j++)
                E[m++]={i,j,get_dist(V[i],V[j])};
        
        kruskal();
        
        printf("%.2f\n",res);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值