[Poj2349]Arctic Network(二分,最小生成樹)
阿新 • • 發佈:2018-07-25
接下來 使用 log 小數 NPU mes poj 國防 sam
[Poj2349]Arctic Network
Description
國防部(DND)要用無線網絡連接北部幾個哨所。兩種不同的通信技術被用於建立網絡:每一個哨所有一個無線電收發器,一些哨所將有一個衛星頻道。
任何兩個有衛星信道的哨所可以通過衛星進行通信,而不管他們的位置。同時,當兩個哨所之間的距離不超過D時可以通過無線電通訊,D取決於對收發器的功率。功率越大,D也越大,但成本更高。出於采購和維修的方便,所有哨所的收發器必須是相同的;那就是說,D值對每一個哨所相同。
你的任務是確定收發器的D的最小值。每對哨所間至少要有一條通信線路(直接或間接)。
Input
輸入的第一行是測試數據的數量N。
每組測試數據的第一行包含衛星頻道的數量S(1 < = S < = 100)和哨所的數量P(S < P < = 500)。接下來的P行,給出以公裏為單位的每個哨所的坐標(x,y)( 坐標為0到10000之間的整數)。
Output
對於每組測試數據,輸出一行,輸出收發器的D的最小值。精確到小數點後兩位。
Sample Input
1
2 4
0 100
0 300
0 600
150 750
Sample Output
212.13
不算很難的題目,在這裏使用的二分,每次二分出最大值,跑一次最小生成樹,判斷聯通塊個數是否>k。時間復雜度:\(O(Tnlogn)\)
這道題還有另一種做法,先直接跑一次最小生成樹,然後找到生成樹上第k+1大的邊。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int read() { int x=0,w=1;char ch=getchar(); while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*w; } const int N=510; int n,k,cnt;double l,r,mid; int x[N],y[N],fa[N]; struct node{ int x,y;double v; }f[N*N]; int gfa(int x){if(x==fa[x])return x;return fa[x]=gfa(fa[x]);} bool cmp(node p,node q){return p.v<q.v;} bool check(double v) { int qwe=0,num=0; for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=cnt;i++) { if(f[i].v>v) break; int xx=gfa(f[i].x),yy=gfa(f[i].y);if(xx==yy)continue; fa[xx]=yy;qwe++;if(qwe==n-1) break; } for(int i=1;i<=n;i++) if(fa[i]==i)num++; return num<=k; } int main() { int t=read(); while(t--) { cnt=0;k=read();n=read(); for(int i=1;i<=n;i++)x[i]=read(),y[i]=read(); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { double dis=sqrt((double)(y[i]-y[j])*(y[i]-y[j])+(x[i]-x[j])*(x[i]-x[j])); f[++cnt].x=i;f[cnt].y=j;f[cnt].v=dis; } sort(f+1,f+1+cnt,cmp); l=0;r=100000; while(r-l>1e-4) { mid=(l+r)/2; if(check(mid)) r=mid; else l=mid; } printf("%.2lf\n",r); } return 0; }
[Poj2349]Arctic Network(二分,最小生成樹)