LaoQiao C/C++ Group B 2020.4 9.通电
Question Link:There is No OJ Link
Question Algorithm:Kruskal
Question Difficulty Level:★☆☆☆☆
Question Description:
【问题描述】
2015年,全中国实现了户户通电。作为一名电力建设者,小明正在帮助一带一路上的国家通电。
这一次,小明要帮助 n 个村庄通电,其中 1 号村庄正好可以建立一个发电站,所发的电足够所有村庄使用。
现在,这
n
n
n 个村庄之间都没有电线相连,小明主要要做的是架设电线连接这些村庄,使得所有村庄都直接或间接的与发电站相通。
小明测量了所有村庄的位置(坐标)和高度,如果要连接两个村庄,小明需要花费两个村庄之间的坐标距离加上高度差的平方,形式化描述为坐标为 (x_1, y_1) 高度为 h_1 的村庄与坐标为 (x_2, y_2) 高度为 h_2 的村庄之间连接的费用为
s
q
r
t
(
(
x
1
−
x
2
)
×
(
x
1
−
x
2
)
+
(
y
1
−
y
2
)
×
(
y
1
−
y
2
)
)
+
(
h
1
−
h
2
)
×
(
h
1
−
h
2
)
sqrt((x_1-x_2)×(x_1-x_2)+(y_1-y_2)×(y_1-y_2))+(h_1-h_2)×(h_1-h_2)
sqrt((x1−x2)×(x1−x2)+(y1−y2)×(y1−y2))+(h1−h2)×(h1−h2)
在上式中 sqrt 表示取括号内的平方根。请注意括号的位置,高度的计算方式与横纵坐标的计算方式不同。
由于经费有限,请帮助小明计算他至少要花费多少费用才能使这 n 个村庄都通电。
【输入格式】
输入的第一行包含一个整数 n ,表示村庄的数量。
接下来 n 行,每个三个整数 x, y, h,分别表示一个村庄的横、纵坐标和高度,其中第一个村庄可以建立发电站。
【输出格式】
输出一行,包含一个实数,四舍五入保留 2 位小数,表示答案。
【样例输入】
4
1 1 3
9 9 7
8 8 6
4 5 4
【样例输出】
17.41
【评测用例规模与约定】
对于 30% 的评测用例,
1
<
=
n
<
=
10
1 <= n <= 10
1<=n<=10
对于 60% 的评测用例,
1
<
=
n
<
=
100
1 <= n <= 100
1<=n<=100
对于所有评测用例,
1
<
=
n
<
=
1000
,
0
<
=
x
,
y
,
h
<
=
10000
1 <= n <= 1000,0 <= x, y, h <= 10000
1<=n<=1000,0<=x,y,h<=10000
Question Analysis:
很明显的最小生成树问题。
Code:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1005,M=N*(N-1);
int p[N];//p[i]记录节点 i 的父节点
int n;
double res=0.0;
struct Loc
{
int x;
int y;
int h;
}loc[M];
struct Edges
{
int a;//Start Point
int b;//End Point
double v;//The Value of the edges
}edge[N];
double cal(Loc a,Loc b)
{
return (double)sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))+(a.h-b.h)*(a.h-b.h);
}
bool cmp(Edges x,Edges y)
{
return x.v<y.v;
}
int find(int x)
{
return p[x]==x ? x : p[x]=find(p[x]);
}
void merge(int x,int y)
{
p[find(x)]=find(y);
}
int main()
{
for (int i = 0; i < N; i++) p[i]=i;
int idx=0;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> loc[i].x >> loc[i].y >> loc[i].h;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
if(i==j) continue;
edge[idx].a=i;
edge[idx].b=j;
edge[idx].v=cal(loc[i],loc[j]);
idx++;
}
sort(edge,edge+idx,cmp);
int cnt=0;//记录已选择边的数量
//在不形成环的条件下依次选择n - 1条边,并把它们的权值相加输出
for (int i = 0; i < idx; i++)
{
int x=edge[i].a,y=edge[i].b;
if(find(x)!=find(y)) //没有成环
{
cnt++;
merge(x,y);
res+=edge[i].v;
if(cnt==n-1) break;
}
}
printf("%.2f",res);
return 0;
}
如有疑问欢迎在评论区留言或者通过Email联系我
My Email:Wizzy-Ang@qq.com
欢迎大家关注我的个人公众号WizzyAngShare,(还有个人博客)我会在这里分享编程语言语法,算法,及区块链的相关知识,还有各种奇奇怪怪的小知识等着你~
虽然现在这个公众号有亿点草率 ,我会努力更新的~~~