Kruskal - Arctic Network - POJ 2349

    技术2025-12-04  12

    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; }
    Processed: 0.016, SQL: 9