Description
Input
Output
Sample Input
1 2 4 0 100 0 300 0 600 150 750
Sample Output
212.13题目大意:DND组织想要通过无线网络把一些哨站连通。他们使用两种不同的科技,一种是卫星通信,另一种是无线电通信。当两个哨点同时拥有卫星通信技术时,他们可以无视距离远近地进行交流,而拥有无线电通信技术的两个哨点必须在距离D以内才能交流。D与无线电波发射器的能量大小有关,当然,能量越大,花的钱越多。现在给出拥有卫星通信技术的哨点数S和拥有无线电通信的哨点数P,求使得所有哨点连通的最短的D。
解题思路:求最小生成树中的第P - S大的权值,感觉用Kruskal算法比较好做一点,因为取边之前已经排好序了,而Prim算法还要再排一次序。
代码如下:
#include
#include
#include
#include
#include
#include
#define EPS 1e-8
const int maxn = 505;
int par[maxn],rank[maxn],x[maxn],y[maxn];
int n,m,cnt;
struct edge
{
int from;
int to;
double dis;
};
edge edges[maxn * maxn];
void init()
{
for(int i = 0;i <= n;i++){
par[i] = i;
}
memset(rank,0,sizeof(rank));
}
int find(int x)
{
return par[x] == x ? x : par[x] = find(par[x]);
}
void unite(int x,int y)
{
x = find(x);
y = find(y);
if(x == y)
return ;
if(rank[x] < rank[y]){
par[x] = y;
}
else{
par[y] = x;
if(rank[x] == rank[y])
rank[x]++;
}
}
bool same(int x,int y)
{
return find(x) == find(y);
}
bool cmp(edge a,edge b)
{
return a.dis < b.dis;
}
double Kruskal()
{
std::sort(edges,edges + cnt,cmp);
init();
double res = 0;
int k = 0;
for(int i = 0;i < cnt;i++){
edge e = edges[i];
if(!same(e.from,e.to)){
unite(e.from,e.to);
if(k == n - m)
break;
res = e.dis;
k++;
}
}
return res;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d %d",&m,&n);
for(int i = 0;i < n;i++){
scanf("%d %d",&x[i],&y[i]);
}
cnt = 0;
for(int i = 0;i < n;i++){
for(int j = i;j < n;j++){
edges[cnt].from = i;
edges[cnt].to = j;
edges[cnt].dis = pow(x[i] - x[j],2.0) + pow(y[i] - y[j],2.0);
cnt++;
}
}
printf("%.2f\n",sqrt(Kruskal()));
}
return 0;
}