D-数据中心
一、题目描述
Example
Input
4
5
1
1 2 3
1 3 4
1 4 5
2 3 8
3 4 2
Output
4
Note
二、思路与算法
本题核心算法为并查集+Kruskal算法。
回忆Kruskal算法:
- 每次挑一条成本最小的边,检查是否合法,合法则加入边集中。
分析题意,核心就是要找到一个最大边权最小的生成树。
那么我们仍然用结构体存储+重载操作符+sort升序排列,每次从结构体数组中取出目前边权最小的一条边。
如果合法则进行合并,同时检查生成树的最大边权是否需要更新。
最终输出最大边权即可。
三、代码实现
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=50005;
const int M=100005;
struct edge{
int u,v,w;
bool operator<(const edge &t)const{ return w<t.w;}
}e[M];
int n,m,rt;
int f[N];
void init(int n){
for(int i=1;i<=n;i++){
f[i]=i;
}
}
int find(int x){
return f[x]==x?x:f[x]=find(f[x]);
}
bool unite(int x,int y){
x=find(x); y=find(y);
if(x==y){return false; }
f[x]=y;
return true;
}
int kruskal_return_max(){
sort(e+1,e+1+m);
int cnt=0,ans=0;
for(int i=1;i<=m;i++){
if(unite(e[i].u,e[i].v)){
ans=max(ans,e[i].w);
if(++cnt==n-1){break; }
}
}
return cnt==n-1?ans:-1;
}
int main(){
scanf("%d%d%d",&n,&m,&rt);
init(n);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
printf("%d\n",kruskal_return_max());
return 0;
}
四、经验与总结
- 求最小的最大边权,可以联想到二分法,每次检查用小于ans的边是否可以包含所有点,如果可以,则ans减小,若无法联通,则ans增大。
最终ans就是可以连通所有点的,最小的最大边权。