P1396
营救
题目背景
“咚咚咚……”“查水表!”原来是查水表来了,现在哪里找这么热心上门的查表员啊!小明感动得热泪盈眶,开起了门……
题目描述
妈妈下班回家,街坊邻居说小明被一群陌生人强行押上了警车!妈妈丰富的经验告诉她小明被带到了 区,而自己在 区。
该市有 条大道连接 个区,一条大道将两个区相连接,每个大道有一个拥挤度。小明的妈妈虽然很着急,但是不愿意拥挤的人潮冲乱了她优雅的步伐。所以请你帮她规划一条从 至 的路线,使得经过道路的拥挤度最大值最小。
输入格式
第一行有四个用空格隔开的 ,,,,其含义见【题目描述】。
接下来 行,每行三个整数 ,表示有一条大道连接区 和区 ,且拥挤度为 。
两个区之间可能存在多条大道。
输出格式
输出一行一个整数,代表最大的拥挤度。
输入输出样例
输入样例 #1
3 3 1 3
1 2 2
2 3 1
1 3 3
输出样例 #1
2
说明/提示
数据规模与约定
- 对于 的数据,保证 。
- 对于 的数据,保证 。
- 对于 的数据,保证 ,,,。且从 出发一定能到达 区。
样例输入输出 1 解释
小明的妈妈要从 号点去 号点,最优路线为 。
题解
1 篇题解
登录后即可使用 Markdown 发布题解。
登录 / 注册YuyiLv.6👑 站长管理员P1396 营救 题解 Author: Yuyi 题意分析 妈妈在 $s$ 区,小明在 $t$ 区。给出一张无向图(可能有重边),每条边有一个“拥挤度”。我们要求出一条从 $s$ 走到 $t$ 的路径,使得这条路径上 拥挤度的最大值 尽可能小。 这是图论中极其经典的 “瓶颈路径” (Bottleneck Path)问题。其实这个问题跟最小生成树(MST)同宗…点击收起题解
YuyiLv.6👑 站长管理员
P1396 营救 题解 Author: Yuyi 题意分析 妈妈在 $s$ 区,小明在 $t$ 区。给出一张无向图(可能有重边),每条边有一个“拥挤度”。我们要求出一条从 $s$ 走到 $t$ 的路径,使得这条路径上 拥挤度的最大值 尽可能小。 这是图论中极其经典的 “瓶颈路径” (Bottleneck Path)问题。其实这个问题跟最小生成树(MST)同宗…点击收起题解
P1396 营救 题解
Author: Yuyi
题意分析
妈妈在 区,小明在 区。给出一张无向图(可能有重边),每条边有一个“拥挤度”。我们要求出一条从 走到 的路径,使得这条路径上拥挤度的最大值尽可能小。 这是图论中极其经典的**“瓶颈路径”**(Bottleneck Path)问题。其实这个问题跟最小生成树(MST)同宗同源,我们完全可以利用 Kruskal 算法 + 并查集 优雅地解决。
正解推导过程
- 贪心排序:因为我们要让路径上的最大拥挤度尽可能小,那么拥挤度小的道路肯定优先走。所以我们将所有边按拥挤度从小到大排序。
- 并查集连通:开始遍历排好序的边,利用并查集将边的两个端点连通。只要加入这条边不会形成环(端点不在同一集合),我们就合并它们。
- 结束判定:在合并的过程中,我们每次都去检查一下起点 和终点 是否已经在同一个连通块中了(即
find(s) == find(t))。一旦它们连通,说明我们已经铺通了一条从 到 的路,由于我们是按从小到大加边的,所以当前加入的这条边的拥挤度,必然就是这条路径上的最大拥挤度,直接输出答案并break即可!
正解代码及分析
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define eps 1e-9
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define lowbit(a) (a)&(-a)
using namespace std;
const int maxn = 20005; // 根据最大边数 m<=20000 统一开辟
const int mo = 998244353;
const double pi = acos(-1.0);
template <typename T>
inline void read(T &X)
{
X = 0;int w = 0; char ch = 0;
while(!isdigit(ch)) {w |= ch == '-' ;ch = getchar();}
while(isdigit(ch)) X = X * 10 + (ch^48),ch = getchar();
if(w) X = -X;
}
int n,m,s,t;
struct Edge
{
int u,v,w;
}e[maxn];
bool cmp(Edge A,Edge B)
{
return A.w < B.w;
}
int fa[maxn];
int find(int u)
{
if(u == fa[u]) return u;
return fa[u] = find(fa[u]);
}
void solve()
{
read(n),read(m),read(s),read(t);
rep(i,1,m) read(e[i].u),read(e[i].v),read(e[i].w);
if(s == t)
{
cout << 0 << endl;
return;
}
rep(i,1,n) fa[i] = i;
sort(e+1,e+1+m,cmp);
rep(i,1,m)
{
int fu = find(e[i].u);
int fv = find(e[i].v);
if(fu != fv)
{
fa[fu] = fv;
}
if(find(s) == find(t))
{
cout << e[i].w << endl;
break;
}
}
return;
}
int main()
{
int T=1;
// freopen("mul.in","r",stdin);
// freopen("mul.out","w",stdout);
// read(T);
while(T--) solve();
return 0;
}
复杂度分析
- 时间复杂度:图中有 条边,对边进行排序耗时 。并查集的单次
find查询和合并由于路径压缩的存在,时间复杂度极其接近 ,最多进行 次循环判定,所以总时间复杂度为 ,在 面前基本可以忽略不计。 - 空间复杂度:由于将点数数组
fa和边集数组e严格依照 用常量maxn = 20005统一齐平开辟,杜绝直接硬编码数字,空间花费只有几百 KB 左右,空间复杂度 ,绝对安全通过。
讨论
0 条讨论
登录后即可使用 Markdown 发起讨论和回复。
登录 / 注册还没有讨论,来发起第一条吧。