算法分析
假设有给定一个d
值,任意两个长度小于等于d
的点,按照最小生成树的方式进行集合合并,形成m
个连通块(m
棵最小生成树),则需要m
个卫星设备
即找一个最小的d
值,使得将所有权值大于d
的边删去,之后,整个图形的连通块的个数等于k
Kruskal算法枚举到的边的长度与连通块个数的函数曲线
Kruskal算法,按照边从小到大枚举对连通块进行合并,随着枚举的边越大,连通块的个数越小
时间复杂度 $O(mlogm)$
参考文献
算法提高课
Java 代码
mport java.util.Arrays;
import java.util.Scanner;
public class Main {
static int N = 510,M = N * N / 2;
static int n,k;
static int m = 0;
static Pair[] pair = new Pair[N];
static Edge[] edge = new Edge[M];
static int[] p = new int[N];
static int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
static double get_dist(Pair a,Pair b)
{
int dx = a.x - b.x;
int dy = a.y - b.y;
return Math.sqrt(dx * dx + dy * dy);
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
k = scan.nextInt();
for(int i = 1;i <= n;i ++)
{
int x = scan.nextInt();
int y = scan.nextInt();
pair[i] = new Pair(x,y);
}
for(int i = 1;i <= n;i ++)
for(int j = 1;j < i;j ++)
edge[m ++] = new Edge(i,j,get_dist(pair[i],pair[j]));
for(int i = 1;i <= n;i ++) p[i] = i;
Arrays.sort(edge,0,m);
int cnt = n;
double res = 0;
for(int i = 0;i < m;i ++)
{
int a = edge[i].a;
int b = edge[i].b;
double w = edge[i].w;
a = find(a);
b = find(b);
if(a != b)
{
p[a] = b;
cnt --;
res = w;
}
if(cnt == k) break;
}
System.out.printf("%.2f",res);
}
}
class Pair
{
int x,y;
Pair(int x,int y)
{
this.x = x;
this.y = y;
}
}
class Edge implements Comparable<Edge>
{
int a,b;
double w;
Edge(int a,int b,double w)
{
this.a = a;
this.b = b;
this.w = w;
}
@Override
public int compareTo(Edge o) {
// TODO 自动生成的方法存根
return Double.compare(w, o.w);
}
}