思路:
- 最小生成树,Kruskal。
- 先分析一波,因为可以任意设置 S 条零花费的道路,那么如果使用单树根的 Prim 恐怕会 WA,应使用以边为本的 Kruskal。一共连 N - S 条边即可,剩下的联通块都使用免费路。
- 枚举所有边,注意枚举严格上三角即可。
代码:
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 505;
int S,N;
double ans;
int par[maxn];
struct NODE{
int x,y;
}node[maxn];
struct EDGE{
int u,v;
double w;
EDGE(int u,int v,double w) : u(u) , v(v) , w(w) {} ;
friend bool operator > (EDGE a,EDGE b)
{
return a.w > b.w;
}
};
priority_queue <EDGE , vector<EDGE> , greater<EDGE> > Q;
void INIT(){
ans = 0;
memset(par , -1 , sizeof(par));
while(Q.size())
Q.pop();
return ;
}
int FIND(int i){
return par[i] == -1 ? i : par[i] = FIND(par[i]);
}
void UNION(int l,int r){
par[r] = l;
return ;
}
void KRUSKAL(){
int cnt = max(N-S , 0);
while(Q.size() && cnt){
EDGE cur = Q.top() ; Q.pop();
int u = cur.u;
int v = cur.v;
double w = cur.w;
int parl = FIND(u);
int parr = FIND(v);
if(parl != parr){
UNION(parl , parr);
ans = max(ans , w);
cnt--;
}
}
return ;
}
int main(){
int T;cin>>T;
while(T--){
INIT();
cin>>S>>N;
for(int i=1;i<=N;i++)
scanf("%d%d" , &node[i].x , &node[i].y);
for(int i=1;i<=N;i++)
for(int j=i+1;j<=N;j++){
double w = sqrt((node[i].x - node[j].x)*(node[i].x - node[j].x) + (node[i].y - node[j].y)*(node[i].y - node[j].y));
Q.push(EDGE(i,j,w));
}
KRUSKAL();
printf("%.2f\n" , ans);
}
return 0;
}