北极通讯网络(kruskal + 贪心)

题目:北极通讯网络

题目链接:https://ac.nowcoder.com/acm/problem/50361

题意:有n个村庄,每个村庄坐标用(x, y)表示,要在村庄间建立通讯网络。有两种通讯工具:

  1. 每个村庄有一台无线电收发机,无线电收发机的参数d是每两个使用无线电收发机通讯的村庄的坐标的距离的最大值。
  2. 有k台卫星设备,有卫星设备的村庄两两之间可以通讯。

问怎么分配k台卫星设备,能够使得无线电收发机的参数d最小。

输入描述:

第一行给出村庄个数n(1 <= n <= 500)和卫星设备台数k(0 <= k <= 100)。

接下来n行,每行两个整数x, y(0 <= x, y <= 10000),第i行表示第i个村庄的坐标。

输出描述:

输出最小的d值,保留两位小数。

样例输入:

3 2

10 10

10 0

30 0

样例输出:

10.00

样例解释:

两台卫星设备给第2,3个村庄,村庄2,3使用卫星设备直接通讯。村庄1和村庄2使用无线电收发机通讯,村庄1,2的距离为10,此时d的值为10。

 

题目分析:最小生成树 + 贪心。可以使用kruskal算法求解。

解题步骤:

  1. 在每两个村庄间都连接一条边,边权为两个村庄的距离。
  2. 做kruskal算法,将最小生成树的边权从小到大用数组dis存起来。
  3. 贪心,长的边所连接的两个村庄用卫星设备直接通讯。有k台卫星设备,当k = 0或k = 1时,通讯设备没办法“抵消”边,即没有两个村庄可以通过卫星设备通讯。此外,k台卫星设备可以抵消k – 1条边,而最小生成树有n – 1条边,那么使用无线电通讯的村庄的最大距离,即d的值为dis[n - k]。

AC代码:

#include<iostream>

#include<vector>

#include<algorithm>

#include<cmath>

 

using namespace std;

const int N = 510;

struct st{

       int x, y;

       double z;

       bool operator < (const st &X) const{

              return z < X.z;

       }

}a[N * N];

struct st2{

       int x, y;

}c[N];

 

int n, k, parent[N];

double dis[N];

 

double Dis(int u, int v){

       int dx = c[u].x - c[v].x;

       int dy = c[u].y - c[v].y;

       return sqrt(dx * dx + dy * dy);

}

 

int find(int x){

       if(x != parent[x]) parent[x] = find(parent[x]);

       return parent[x];

}

 

void Union(int x, int y){

       parent[find(x)] = find(y);

}

 

void solve(){

       scanf("%d %d", &n, &k);

       for(int i = 1;i <= n;i++){

              parent[i] = i;

              scanf("%d %d", &c[i].x, &c[i].y);

       }

      

       int cnt = 1;

       for(int i = 1;i <= n;i++){

              for(int j = i + 1;j <= n;j++){

                     a[cnt++] = {i, j, Dis(i, j)};

              }

       }

       sort(a + 1, a + cnt);

      

       int count = 1;

       for(int i = 1;i < cnt;i++){

              if(find(a[i].x) != find(a[i].y)){

                     Union(a[i].x, a[i].y);

                     dis[count] = a[i].z;

                     count++;

                    

                     if(count == n) break;

              }

       }

       printf("%.2lf\n", dis[n - k]);

}

 

int main(void){

       solve();

   

    return 0;

}

时间复杂度:O(n ^ 3)。

空间复杂度:O(n ^ 2)。

posted @ 2021-11-20 00:38  思丶君  阅读(200)  评论(0)    收藏  举报