问题描述
2015年,全中国实现了户户通电。作为一名电力建设者,小明正在帮助一带一路上的国家通电。
这一次,小明要帮助 n 个村庄通电,其中 1 号村庄正好可以建立一个发电站,所发的电足够所有村庄使用。
现在,这 n 个村庄之间都没有电线相连,小明主要要做的是架设电线连接这些村庄,使得所有村庄都直接或间接的与发电站相通。
小明测量了所有村庄的位置(坐标)和高度,如果要连接两个村庄,小明需要花费两个村庄之间的坐标距离加上高度差的平方,形式化描述为坐标为 (x_1, y_1) 高度为 h_1 的村庄与坐标为 (x_2, y_2) 高度为 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 表示取括号内的平方根。请注意括号的位置,高度的计算方式与横纵坐标的计算方式不同。
由于经费有限,请帮助小明计算他至少要花费多少费用才能使这 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;
对于 60% 的评测用例,1 <= n <= 100;
对于所有评测用例,1 <= n <= 1000,0 <= x, y, h <= 10000。
分析
无向网的最小生成树问题
prim算法,选点,适合边多的网,时间复杂度O(n^2) 不会超时
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Scanner;
class Main
{
public static void main(String[] args)
{
Scanner sc =new Scanner(System.in);
int n=sc.nextInt();
Ver[] graph= new Ver[n];
for (int i = 0; i < n; i++)
{
graph[i]=new Ver(sc.nextDouble(), sc.nextDouble(), sc.nextDouble());
}
double dis[] =new double[n];
//初始化
for (int i = 1; i < n; i++)
{
dis[i]=graph[0].getDis(graph[i]);
}
double ans =0;
for (int i = 1; i < n; i++)
{
int cur =getMin(dis);
ans+=dis[cur];
dis[cur]=0;
for (int j = 0; j < n; j++)
{
if(dis[j]!=0&&graph[cur].getDis(graph[j])<dis[j])
dis[j]=graph[cur].getDis(graph[j]);
}
}
System.out.printf("%.2f",ans);
}
static int getMin(double[] a)
{
int tar =0;
double min= Double.MAX_VALUE;
for (int i = 0; i < a.length; i++)
{
if(min>a[i]&&a[i]!=0)
{
min=a[i];
tar=i;
}
}
return tar;
}
static class Ver//定义节点
{
double x,y,h;
public Ver(double x,double y,double h)
{
// TODO Auto-generated constructor stub
this.x=x;
this.y=y;
this.h=h;
}
public double getDis(Ver a)
{
return Math.sqrt((a.x-x)*(a.x-x)+(a.y-y)*(a.y-y))+(a.h-h)*(a.h-h);
}
}
}
Kruscal算法,选边,适合边少的,时间复杂度O(eloge)主要在排序上
import java.util.Arrays;
import java.util.Scanner;
class Main
{
public static void main(String[] args)
{
Scanner sc =new Scanner(System.in);
int n=sc.nextInt();
Ver[] graph= new Ver[n];
int[] father = new int[n];//找祖先
for (int i = 0; i < n; i++)
{
graph[i]=new Ver(sc.nextDouble(), sc.nextDouble(), sc.nextDouble());
father[i]=i;
}
Road[] roads =new Road[(n-1)*n/2];
//初始化
for (int i = 0,cur=0; i < n-1; i++)
{
for (int j = i+1; j < n; j++)
{
roads[cur]=new Road(i, j,graph);
cur++;
}
}
double ans =0;
Arrays.sort(roads);
for (int i = 0; i < roads.length; i++)
{
System.out.println(roads[i].dis);
}
//kruscal算法
for (int i = 0,num=0; i < roads.length; i++,num++)
{
if(num==n-1) break;
int a=fatch(roads[i].from,father);
int b=fatch(roads[i].to,father);
if(a!=b)
{
ans+=roads[i].dis;
father[a]=b;
}
}
System.out.printf("%.2f",ans);
}
private static int fatch(int a, int[] father)
{
// TODO Auto-generated method stub
while(father[a]!=a)
{
a=father[a];
}
return a;
}
static class Road implements Comparable<Road>//定义边
{
int from;
int to;
double dis;
public Road(int i, int j, Ver[] graph)
{
// TODO Auto-generated constructor stub
this.from = i;
this.to = j;
this.dis=graph[from].getDis(graph[to]);
}
public int compareTo(Road x)
{
double d= (this.dis-x.dis);
if(d>0) return 1;
if(d==0) return 0;
return -1;
}
}
static class Ver//定义节点
{
double x,y,h;
public Ver(double x,double y,double h)
{
// TODO Auto-generated constructor stub
this.x=x;
this.y=y;
this.h=h;
}
public double getDis(Ver a)
{
return Math.sqrt((a.x-x)*(a.x-x)+(a.y-y)*(a.y-y))+(a.h-h)*(a.h-h);
}
}
}