洛谷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,表示无线电收发器的最小传输距离,精确到小数点后两位。
输入输出样例
2 4 0 100 0 300 0 600 150 750
212.13
说明/提示
对于 20% 的数据:P = 2,S = 1
对于另外 20% 的数据:P = 4,S = 2
对于 100% 的数据保证:1 ≤ S ≤ 100,S < P ≤ 500,0 ≤ x,y ≤ 10000。
差不多是最小生成树裸题了...一开始没看到“直接或间接”,想了一晚上QnQ...有了这一句话,假设没有卫星电话这个条件,能看出来求的就是最小生成树的最大边。那么卫星电话是干啥用的呢?就是删边用的。当删除最小生成树的m条边后,最小生成树会被划分成m+1个树形区域(即连通块)。基于卫星电话的特性,两个连通块是可以用一组卫星电话连接的,所以s个卫星电话可以连接s个连通块,将最小生成树分成s个连通块需要删除s-1条边,而最小生成树共有p-1条边,因此跑Kruskal时,只需要统计前(s-1)-(p-1)=s-p条边里的最大值即可。
#include <bits/stdc++.h> using namespace std; int s,p; int fa[505]={0}; struct point { int num; double x; double y; }po[505]; struct rec { int x; int y; double z; }edge[250005]; int tot=0; bool cmp(rec a,rec b) { return a.z<b.z; } int get(int x) { if(x==fa[x])return x; return fa[x]=get(fa[x]); } double calc(double x1,double y1,double x2,double y2)//求两点间距离 { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } double mmax(double a,double b) { return a>b?a:b; } int main() { cin>>s>>p; int i,j; for(i=1;i<=p;i++)fa[i]=i; for(i=1;i<=p;i++) { po[i].num=i; cin>>po[i].x>>po[i].y; } for(i=1;i<=p;i++)//先建立一个完全图,在完全图上跑 Kruskal { for(j=i;j<=p;j++) { double temp=calc(po[i].x,po[i].y,po[j].x,po[j].y); if(temp) { tot++; edge[tot].x=po[i].num; edge[tot].y=po[j].num; edge[tot].z=temp; } } } sort(edge+1,edge+tot+1,cmp); double ans=0; int cnt=0; for(i=1;i<=tot;i++) { if(cnt==p-s)break;//建立完前p-s条边时即可break int x=get(edge[i].x); int y=get(edge[i].y); if(x==y)continue; fa[x]=y; cnt++; ans=mmax(ans,edge[i].z); } printf("%.2lf",ans); return 0; }