思路:
最小生成树 ,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 ;
}