无线通讯网——kruskal算法
P1991 无线通讯网 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这道题看着很复杂,需要读几遍题才理解。题意可以转化为在图里去掉k-1条最小边后,第k条最小边即为答案。
因为在图中去掉n条边,就会得到n+1个连通块。那么就把所有哨所划分成了n+1个连通块,我们只需要在每个连通块里放一个卫星,这样不同连通块可以通过卫星联系,而每个连通块内部的哨所可以通过无线电来联系。所以当我们用kruskal算法将每个哨所之间的距离从小到大排好序后,因为有s个卫星、p个哨所,所以我们只需要将刚开始初始化的p个连通块用并查集转化为s个连通块就可以保证上述卫星与无线电的要求了。而为了转化为s个连通块,我们应该进行p-s次并查集的合并。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=3e5,M=600; 4 int s,q,x[M],y[M],idx,p[M]; 5 struct node 6 { 7 int a,b; 8 double w; 9 }e[N]; 10 11 bool cmp(const node&s1,const node&s2) 12 { 13 return s1.w<s2.w; 14 } 15 16 double juli(int i,int j) 17 { 18 double xx=(double)(x[i]-x[j]); 19 double yy=(double)(y[i]-y[j]); 20 return sqrt(xx*xx+yy*yy); 21 } 22 23 int find(int x) 24 { 25 if(p[x]!=x)p[x]=find(p[x]); 26 return p[x]; 27 } 28 29 void kruskal() 30 { 31 sort(e+1,e+idx+1,cmp); 32 for(int i=1;i<=q;i++)p[i]=i; 33 34 int k=0;double ans=0; 35 for(int i=1;i<=idx;i++) 36 { 37 int a=e[i].a,b=e[i].b; 38 double w=e[i].w; 39 if(find(a)!=find(b)) 40 { 41 k++; 42 ans=w; 43 p[find(a)]=find(b); 44 } 45 if(k>=q-s) //有s个连通块 46 { 47 printf("%.2lf\n",ans); 48 return ; 49 } 50 } 51 } 52 53 int main() 54 { 55 scanf("%d%d",&s,&q); 56 for(int i=1;i<=q;i++)scanf("%d%d",&x[i],&y[i]); 57 58 for(int i=1;i<=q;i++) 59 { 60 for(int j=i+1;j<=q;j++) 61 { 62 double ww=juli(i,j); 63 e[++idx].a=i,e[idx].b=j,e[idx].w=ww; 64 } 65 } 66 67 kruskal(); 68 69 return 0; 70 }