题目node
这一题对我有历史性的意义,由于我深入意识到:c++
不要用namespace!算法
不要用namespace!spa
不要用namespace!code
写此题解,以示他人。get
(搞错重点了吧喂!)it
好,回归正题:io
这道题的思路是这样:模板
首先,用Kruskal算法。class
(建议先把 并查集模板与 最小生成树模板 打了再继续看)
咱们回顾一下Kruskal算法的过程:
把边按权值从小到大一条条排好,而后再从未选择的点中添加边,一直添加到节点数-1为止。
重点:为何是节点数-1?由于最小生成树要让图连通。
可不能够不连通?
能够!
该题中,卫星电话的存在,就是为了能够让图断开。而最后求的最大边,就是最后一个添加到图中的边。
附上代码:
#include <bits/stdc++.h> #define MAXN 200005 int node,edgenum=0,ans=0,k=0,s; int fat[MAXN],siz[MAXN]; //坐标 struct pair { int first,second; } a[MAXN]; //图 struct EDGE { int from,to;double cost; } e[MAXN]; //比较器 bool cmp(EDGE a,EDGE b) {return a.cost<b.cost;} //并查集 + 路径压缩 + 启发式搜索 int Find(int x){ return (fat[x]==x)? x : fat[x]=Find(fat[x]); } void unionn(int x,int y){ x=Find(x); y=Find(y); if(siz[x]>siz[y]) std::swap(x,y); fat[x]=y; siz[y]+=siz[x]; } //两点之间距离公式 double distance(pair m , pair n) { double ans=std::sqrt( (m.first-n.first)*(m.first-n.first) + (m.second-n.second)*(m.second-n.second) ); return ans; } int main() { double d; std::scanf("%d%d",&s,&node); for(int i=1;i<=node;++i) scanf("%d%d",&a[i].first,&a[i].second); for(int i=1;i<=node;++i) {fat[i]=i; siz[i]=1;} //初始化 for(int i=1;i<=node;++i) //构图 { for(int j=i+1;j<=node;++j) { e[ ++edgenum ].from=i; e[ edgenum ].to=j; e[ edgenum ].cost=distance(a[i],a[j]); } } // Kurskal std::sort(e+1,e+edgenum+1,cmp); for(int i=1;i<=edgenum;++i) { if(k==node-s) break;//节点数-卫星电话数 if(Find(e[i].from) != Find(e[i].to)) { unionn(e[i].from,e[i].to); d=e[i].cost; ++k; } } std::printf("%.2lf",d); return 0; }
其实这题的数据有点弱。
个人代码是有缺陷的,但是AC了。
应该还要再添加一些特判。
好比,当卫星电话数大于节点数时,d应该为0。
当卫星电话数为0时,应该与卫星电话为1时的状况相等。