题目描述
题目分析
csp通病,balabala说一堆,实际上就是给定无向图,求解一颗生成树,使得最大边权最小。
即求一棵最小瓶颈生成树,由性质知最小生成树一定是最小瓶颈生成树。
问题转化为求一棵最小生成树,并记录其中最大边权。题目中“数据中心”属于无用信息。
上一题已经用了Prim,本题使用Kruskal板子跑一遍即可。
一些感悟
对比了自己的Kruskal和学长的Kruskal,深深自愧不如。下面来分析分析一些好的point:
- 重载<可以放在结构体中一行解决,避免写cmp函数(不过考虑到个人习惯我还是喜欢使用cmp比较函数),常用const修饰变量和函数以防止莫名奇妙的修改。
struct edge
{
int u, v, w;
bool operator <(const edge& t)const { return w < t.w; }//不使用cmp比较函数的重载方法
}e[100009];
- 巧用函数的返回值。操作类函数中,我常常喜欢使用void类型,但有时可能需要额外数组记录信息。例如在unite()函数中,返回值为bool类型可以直接判断是否要进行后续操作。
bool unite(int x, int y)
{
x = find(x); y = find(y);
if (x == y)return false;//已经在一组
parent[x] = y; return true;//不在一组,合并
}
代码
#include <iostream>
#include<algorithm>
using namespace std;
struct edge
{
int u, v, w;
bool operator <(const edge& t)const { return w < t.w; }//不使用cmp比较函数的重载方法
}e[100009];
int parent[50009];
void init(int n)
{
for (int i = 1; i <= n; i++)parent[i] = i;
}
int find(int x)
{
return parent[x] == x ? x : parent[x] = find(parent[x]);
}
bool unite(int x, int y)
{
x = find(x); y = find(y);
if (x == y)return false;//已经在一组
parent[x] = y; return true;//不在一组,合并
}
int n, m, start;//n个节点m条边,数据中心为start(貌似start没什么用)
int kruskalReturnMax()
{
sort(e + 1, e + m + 1);
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;//生成树m=n-1,及时终止提高速度
}
}
return cnt == n-1 ? ans : -1;//成功生成返回ans,否则返回-1
}
int main()
{
cin >> n >> m >> start;
init(n);
for (int i = 1; i <=m; i++)
cin >> e[i].u >> e[i].v >> e[i].w;
cout << kruskalReturnMax();
return 0;
}