首先基本的最小生成树
然后去掉S-1条最长的边
这里为什么要去掉S-1条,想了半天才想通。。。唉,废柴。。起初我想,对每一条边要考虑,如果两个点都没有卫星,就去掉两个卫星;如果其中一个点没有卫星,另一个有,则去掉一个卫星,如果都有卫星,跳过。
后来发现。。在某个点有了卫星以后,如果又碰到一条边,只需要将这条边中的任意一个顶点安置卫星,就相当于该点已经通过卫星连通,即,不需要使用两颗卫星,当然,第一条边除外。所以是去掉S-1条边
剩下的最长的边的长度就是
我尽量让代码好看一点
#include<iostream>
#include<vector>
#include<math.h>
#include<algorithm>
using namespace std;
struct Point{
int x,y;
Point(int x1,int y1):x(x1),y(y1){}
};
struct Edge{
int start;
int end;
double distance;
Edge(int s,int e,double d):start(s),end(e),distance(d){}
};
int satelite;
int n;
vector<Point> outpost;
vector<Edge> edge;
double getDistance(int i,int j){
Point p1 = outpost[i];
Point p2 = outpost[j];
int x = p2.x-p1.x;
int y = p2.y-p1.y;
return sqrt(double(x*x+y*y));
}
bool comp(const Edge &e1,const Edge &e2){
return e2.distance>e1.distance;
}
vector<Edge> candi;
int index;
void prim(){
vector<bool> used;
for(int i=0;i<n;i++)
used.push_back(false);
used[0] = true;
while(1){
for(int i=0;i<edge.size();i++){
if((!used[edge[i].start] && used[edge[i].end]) || (!used[edge[i].end] && used[edge[i].start])){
if(used[edge[i].start])
used[edge[i].end]=true;
else
used[edge[i].start]=true;
candi.push_back(edge[i]);
break;
}
}
if(candi.size()==n-1)
break;
}
sort(candi.begin(),candi.end(),comp);
}
int main(){
int caseNum;
scanf("%d",&caseNum);
while(caseNum--){
scanf("%d",&satelite);
scanf("%d",&n);
for(int i=0;i<n;i++){
int a,b;
scanf("%d",&a);
scanf("%d",&b);
outpost.push_back(Point(a,b));
}
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
edge.push_back(Edge(i,j,getDistance(i,j)));
}
}
sort(edge.begin(),edge.end(),comp);
prim();
printf("%.2f\n",candi[candi.size()-1-satelite+1].distance);
outpost.clear();
edge.clear();
candi.clear();
}
return 0;
}