題目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時的狀況相等。