【习题】【最小生成树习题】LaoQiao C/C++ Group B 2020.4 9.通电

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((x1x2)×(x1x2)+(y1y2)×(y1y2))+(h1h2)×(h1h2)
  在上式中 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<=10000<=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,(还有个人博客)

我会在这里分享编程语言语法,算法,及区块链的相关知识,还有各种奇奇怪怪的小知识等着你~

QRCode
虽然现在这个公众号有亿点草率 ,我会努力更新的~~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值