[2019北大机试G]:Arctic Network(最小生成树+并查集)

总时间限制: 
2000ms
 
内存限制: 
65536kB
描述
The Department of National Defence (DND) wishes to connect several northern outposts by a wireless network. Two different communication technologies are to be used in establishing the network: every outpost will have a radio transceiver and some outposts will in addition have a satellite channel.
Any two outposts with a satellite channel can communicate via the satellite, regardless of their location. Otherwise, two outposts can communicate by radio only if the distance between them does not exceed D, which depends of the power of the transceivers. Higher power yields higher D but costs more. Due to purchasing and maintenance considerations, the transceivers at the outposts must be identical; that is, the value of D is the same for every pair of outposts.

Your job is to determine the minimum D required for the transceivers. There must be at least one communication path (direct or indirect) between every pair of outposts.
输入
The first line of input contains N, the number of test cases. The first line of each test case contains 1 <= S <= 100, the number of satellite channels, and S < P <= 500, the number of outposts. P lines follow, giving the (x,y) coordinates of each outpost in km (coordinates are integers between 0 and 10,000).
输出
For each case, output should consist of a single line giving the minimum D required to connect the network. Output should be specified to 2 decimal points.
样例输入
1
2 4
0 100
0 300
0 600
150 750
样例输出
212.13
来源
Waterloo local 2002.09.28
  很容易想到使用最小生成树,问题在于这S个satellite channels,一开始的想法是不能简单地从最小生成树中删去最大的S-1条边,因为这S个点在最小生成树上有可能彼此不相邻。后来发现应该从连通分量的角度去考虑,在使用kruskal算法生成最小生成树时,当图中联通分量的个数为S(即算法处理了n-s条边)时,可以将这S个连通分量中的任意一个点标记为satellite channels,即可满足题目要求,故只需输出已经处理的这n-s条边中最大的即可。
通过本题顺便回顾最小生成树算法:
kruskal算法:    

1).记Graph中有v个顶点。e个边

2).新建图Graphnew,Graphnew中拥有原图中同样的e个顶点,但没有边

3).将原图Graph中全部e个边按权值从小到大排序

4).循环:从权值最小的边开始遍历每条边 直至图Graph中全部的节点都在同一个连通分量中

                if 这条边连接的两个节点于图Graphnew中不在同一个连通分量中

                                         增加这条边到图Graphnew

 

Prim算法:

1).输入:一个加权连通图。当中顶点集合为V,边集合为E;

2).初始化:Vnew = {x},当中x为集合V中的任一节点(起始点),Enew = {},为空;

3).反复下列操作,直到Vnew = V:

a.在集合E中选取权值最小的边<u, v>,当中u为集合Vnew中的元素。而v不在Vnew集合当中。而且v∈V(如果存在有多条满足前述条件即具有同样权值的边,则可随意选取当中之中的一个);

b.将v增加集合Vnew中,将<u, v>边增加集合Enew中。

4).输出:使用集合Vnew和Enew来描写叙述所得到的最小生成树。

 

本题使用的是kruskal算法。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <cmath>
 6 #include <cstdlib>
 7 #include <algorithm>
 8 using namespace std;
 9 int T,s,n;
10 int x[505],y[505];
11 struct Edge{
12     int from,to;
13     double w;
14 }edge[300005];
15 int tol;
16 int fa[505];
17 void init(){
18     tol = 0;
19     for (int i  = 0;i < n;++i) fa[i] = i;
20 }
21 
22 double dis(int i,int j){
23     return sqrt((x[i]-x[j])*(x[i]-x[j]) + (y[i] - y[j]) * (y[i]-y[j]));
24 }
25 
26 void addedge(int u,int v,double w){
27     edge[tol++] = Edge{u,v,w};
28 }
29 
30 int getfa(int x){
31     return ((x == fa[x]) ? x : fa[x] = getfa(fa[x]));
32 }
33 
34 void Union(int x,int y){
35     x = getfa(x);
36     y = getfa(y);
37     fa[x] = y;
38 }
39 
40 double kruskal(){
41     double ans = 0;
42     int pos = 0;
43     for (int i = 0;i < n-s;++i){
44         while(getfa(edge[pos].from) == getfa(edge[pos].to)) pos++;
45         Union(edge[pos].from,edge[pos].to);
46         ans = edge[pos].w;
47     }
48     return ans;
49 }
50 
51 bool cmp(Edge e1,Edge e2){
52     return e1.w < e2.w;
53 }
54 
55 int main(){
56     scanf("%d",&T);
57     while(T--){
58         scanf("%d%d",&s,&n);
59         for (int i = 0;i < n;++i){
60             scanf("%d%d",x+i,y+i);
61         }
62         init();
63         for (int i = 0;i < n-1;++i){
64             for (int j = i+1;j < n;++j){
65                 addedge(i,j,dis(i,j));
66             }
67         }
68         sort(edge,edge+tol,cmp);
69         printf("%.2f\n",kruskal());
70     }
71 }

 

posted @ 2020-02-03 19:23  mizersy  阅读(269)  评论(0编辑  收藏  举报