【题解】洛谷P1396 营救
【题解】洛谷P1396 营救
一道并查集+二分的题。(刷水题找信心
看到最大的最小就想到二分。那就稍微看看单调性:
易得存在一个满足题意的拥挤度 \(w\) ,并且使得 \(w-1\) 不满足题意,而 \(w+1\) 满足题意。稍微想想可知此题满足二分的单调性,就可以二分 \(w\) 来求解。
考虑二分的检查函数,题目只要求我们判断图上两个节点是否连通,那么用并查集维护即可。
代码:
#include<bits/stdc++.h>
const int maxn = 2e4 + 10;
struct node // 存储边的结构体
{
int x, y, w;
} a[maxn];
int father[maxn], n, m, s, t;
// 并查集模板
void init(int size) // 初始化
{
for (int i = 0; i <= size; i++)
father[i] = i;
}
int find(int x) // 找祖先
{
if (father[x] != x)
father[x] = find(father[x]);
return father[x];
}
void uni(int x, int y) // 合并
{
x = find(x);
y = find(y);
father[x] = y;
}
bool check() { return find(s) == find(t); } // 找是否有公共祖先
bool solve(int x) // 二分的判断函数
{
init(m);
for (int i = 0; i < m; i++)
if (a[i].w <= x)
uni(a[i].x, a[i].y); // 不超过 x 的连起来
if (check())
return true;
else
return false;
}
int main()
{
scanf("%d%d%d%d", &n, &m, &s, &t);
for (int i = 0; i < m; i++)
scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].w);
int l = 1, r = -10;
for (int i = 0; i < m; i++)
r = std::max(r, a[i].w); // 找二分边界:最大的 w
while (l <= r) // 我习惯写闭区间的二分
{
int mid = (l + r) / 2;
if (solve(mid)) // mid 满足要求说明 w 还可以更小
r = mid - 1;
else
l = mid + 1;
}
if (solve(r)) // 结束后 r 更小,这么写省点麻烦
printf("%d\n", r);
else
printf("%d\n", l);
return 0;
}