题目链接:http://poj.org/problem?id=2349
先求出每两个顶点之间的距离,(注意:是double类型的),然后用普里姆算法(Prim)求最小生成树。由于无线电的数目已给出m,所以需要把最小生成树分成m份,即删除m-1条边,得到m个连通分量。关键是删除哪些边呢,题目要求最小的D,故把构成最小生成树的边从大到小排序,删除前m-1条边,第m条边即所要求的最小D。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 2100
int N,M;
double a[maxn][maxn];
int v[maxn];
double ans[maxn];
double dis[maxn];
int k;
struct point
{
int x,y;
}p[maxn];
double dit(int i,int j)
{
return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
}
void prim(int s)
{
for(int i=2;i<=M;i++)
dis[i] = a[s][i];
dis[s] = 0;
v[s] = 1;
int index;
for(int i=1;i<M;i++)
{
double Min = INF;
for(int j=1;j<=M;j++)
{
if(!v[j]&&dis[j]<Min)
{
Min = dis[j];
index = j;
}
}
ans[k++] = Min;
v[index] = 1;
for(int j=1;j<=M;j++)
{
if(dis[j]>a[index][j])
dis[j] = a[index][j];
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
k = 0;
memset(ans,0,sizeof(ans));
memset(v,0,sizeof(v));
scanf("%d%d",&N,&M);
for(int i=1; i<=M; i++)
scanf("%d%d",&p[i].x,&p[i].y);
for(int i=1;i<M;i++)
for(int j=i;j<=M;j++)
{
if(i == j)
a[i][j] = INF;
else
a[i][j] = a[j][i] = dit(i,j);
}
prim(1);
sort(ans,ans+M);
printf("%.2f
",ans[M-N]);
}
return 0;
}