链接网址:http://poj.org/problem?id=2349
题意:有卫星电台的城市之间可以任意联络。没有卫星电台的城市只能和距离小于等于D的城市联络。题目告诉你卫星电台的个数S,让你求最小的D.做最小生成树,去掉最长的S条边后,剩下最长的边就是D.也就是求最小生成树中第S+1长的边。
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define MAX 505 //图的最大顶点个数
#define MAXCOST 0x7fffffff //表示无穷大
double graph[MAX][MAX]; // 存放图的邻接矩阵 ,其中0行0列不用
int max = 0; // 存放最小生成树中的最大边权值
struct point
{
double x,y;
}pp[MAX];
struct Point
{
int start, end; //每条边的两个顶点
double d;
bool operator<(const Point &a)const
{
return d < a.d;
}
}p[MAX];
// 存放最小生成树的边
double dist(point a,point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void Prim(int n) //从顶点1开始用PRIM算法求顶点个数为n的图的最小生成树
{
double lowcost[MAX],min; //用来存放边的权的数组
int mst[MAX]; //用来存放最小边的第1个顶点
int minid; //存放当前最小的权、最小权边的第2个顶点
int count= 0; //计数已求出的边数
int i, j;
for (i = 2; i <= n; i++) //初始化 数组 lowcost 和数组mst
{
lowcost[i] = graph[1][i];
mst[i] = 1; //=====所有边的第1顶点为第1个顶点
}
for (i = 2; i <= n; i++)
{
min = MAXCOST;
minid = 0; //?? ===
for (j = 2; j <= n; j++) //根据数组 lowcost 和 数组mst 来计算当前最小边的权 和 第2个顶点
if (lowcost[j] < min && lowcost[j] != 0) // lowcost[j] != 0 表示顶点j为未连通的顶点
{
min = lowcost[j];
minid = j;
}
count++; // 边数
p[count].start = mst[minid];//====
p[count].end = minid; //===保存边的两个顶点
p[count].d=lowcost[minid];
//if (lowcost[minid] > max) max = lowcost[minid]; // 修改最小生成树中的最大边的权值
// printf("p[%d].d: %.2f\n",count,p[count].d);
lowcost[minid] = 0; //标记该边已经使用,即第2个顶点minid为已经连通的顶点
for (j = 2; j <= n; j++) //根据图的邻接矩阵修改 数组 lowcost 和 数组mst
if (graph[minid][j] < lowcost[j])
{
lowcost[j] = graph[minid][j];
mst[j] = minid; //===表示两个相连的顶点
}
}
}
int main()
{
int i,j,t,s,n;
cin>>t;
while(t--)
{
cin>>s>>n;
for(i=1;i<=n;i++)
cin>>pp[i].x>>pp[i].y;
for(i=1;i<=n;i++) //构建邻接矩阵
for(j=1;j<i;j++)
graph[i][j]=graph[j][i]=dist(pp[i],pp[j]);
for(i=1;i<=n;i++)
graph[i][i]=1<<30;
Prim(n);
sort(p,p+n);//从小到大排序
//cout<<endl;
//for(i=1;i<=n-1;i++)
//printf("p[%d].d: %.2f\n",i,p[i].d);
cout.setf(ios::fixed);//保留两位小数
cout.precision(2);
cout<<p[n-s].d<<endl
}
return 0;
}