题目链接:https://www.luogu.org/problem/P1991
题目:
国防部计划用无线网络连接若干个边防哨所。2 种不同的通讯技术用来搭建无线网络;
每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。
任意两个配备了一条卫星电话线路的哨所(两边都ᤕ有卫星电话)均可以通话,无论他们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过 D,这是受收发器的功率限制。收发器的功率越高,通话距离 D 会更远,但同时价格也会更贵。
收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个 D。你的任务是确定收发器必须的最小通话距离 D,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。
输入格式
从 wireless.in 中输入数据第 1 行,2 个整数 S 和 P,S 表示可安装的卫星电话的哨所数,P 表示边防哨所的数量。接下里 P 行,每行两个整数 x,y 描述一个哨所的平面坐标(x, y),以 km 为单位。
输出格式
输出 wireless.out 中
第 1 行,1 个实数 D,表示无线电收发器的最小传输距离,精确到小数点后两位。
输入输出样例
输入 #1复制
2 4
0 100
0 300
0 600
150 750
输出 #1复制
212.13
说明/提示
对于 20% 的数据:P = 2,S = 1
对于另外 20% 的数据:P = 4,S = 2
对于 100% 的数据保证:1 ≤ S ≤ 100,S < P ≤ 500,0 ≤ x,y ≤ 10000。
解题思路:
利用最小生成树解题,按照 克鲁斯卡尔算法(Kruskal) 的思路解题,普通的最小生成树中有p-1条边,而此题只需转化为求解较小的p-n条边,因为有n个卫星电话,所以可以去掉n-1条较大的边。
注意:两点之间只要间接或直接连即可。
例如当p=6,s=4时,只需要选出较小的两条边即可,下图中打叉号的那两条边即是。
图中圈出的点是放置卫星电话的地方,这样放置即可满足所有点直接或间接相连。
所以可总结出来 求较小的p-n条边即可 (看的他人的题解这样说的)
附上AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
int n,m;
const int INF=505;
int a[INF];
int vis[INF]={0};
struct node{
int from,to;
double d;
}f[INF*INF];
struct Node{
int x;
int y;
}g[INF];
bool cmp(node p1,node p2)
{
return p1.d <p2.d ;
}
void init()
{
int i;
for(i=0;i<=m;i++)
{
a[i]=i;
}
}
int find(int x)
{
if(x==a[x]){
return a[x];
}
else {
return find(a[x]);
}
}
bool judge(int x,int y)//并查集判断是否成环
{
int xx=find(x);
int yy=find(y);
if(xx==yy)
{
return false;
}
else {
a[xx]=yy;
return true;
}
}
int main()
{
scanf("%d%d",&n,&m);
init();
int cnt=0;
for(int i=1;i<=m;i++)
{
int j,k;
scanf("%d%d",&j,&k);
g[i].x =j;
g[i].y =k;
}
for(int i=1;i<=m;i++)
{
for(int j=i+1;j<=m;j++)
{
double c;
int x=(g[i].x -g[j].x )*(g[i].x -g[j].x );
int y=(g[i].y -g[j].y )*(g[i].y -g[j].y );
c=(double)x+(double)y;
f[++cnt].from =i;
f[cnt].to =j;
f[cnt].d =sqrt(c);
}
}
sort(f+1,f+cnt+1,cmp);
int sum=1;
double ans=0;
for(int i=1;i<=cnt&&sum<=m-n;i++)
{
if(judge(f[i].from ,f[i].to )){
ans=max(ans,f[i].d );
sum++;
}
}
printf("%.2lf",ans );
return 0;
}