题目背景
“咚咚咚……”“查水表!”原来是查水表来了,现在哪里找这么热心上门的查表员啊!小明感动得热泪盈眶,开起了门……
题目描述
妈妈下班回家,街坊邻居说小明被一群陌生人强行押上了警车!妈妈丰富的经验告诉她小明被带到了 t 区,而自己在 s 区。
该市有 m 条大道连接 n 个区,一条大道将两个区相连接,每个大道有一个拥挤度。小明的妈妈虽然很着急,但是不愿意拥挤的人潮冲乱了她优雅的步伐。所以请你帮她规划一条从 s 至 t 的路线,使得经过道路的拥挤度最大值最小。
输入格式
第一行有四个用空格隔开的 n,m,s,t,其含义见【题目描述】。
接下来 m 行,每行三个整数 u,v,w,表示有一条大道连接区 u 和区 v,且拥挤度为 w。
两个区之间可能存在多条大道。
输出格式
输出一行一个整数,代表最大的拥挤度。
输入输出样例
输入 #1
3 3 1 3
1 2 2
2 3 1
1 3 3
输出 #1
2
说明/提示
数据规模与约定
- 对于 30% 的数据,保证 n≤10。
- 对于 60% 的数据,保证 n≤100。
- 对于 100% 的数据,保证 1≤n≤104,1≤m≤2×104,w≤104,1≤s,t≤n。且从 s 出发一定能到达 t 区。
样例输入输出 1 解释
小明的妈妈要从 11 号点去 33 号点,最优路线为 11->22->33。
分析
Kruskal算法求最小生成树
题目分析
题目要求规划一条从 s 至 t 的路线,使得经过道路的拥挤度最大值最小。也就是求出包含s,t节点的最小生成树的最大权值。
只需套用Kruskal算法,当s,t节点的父节点相同时(在同一集合中),当前正在添加的那一条边的权值就是最小生成树的最大权值
Kruskal算法
Kruskal算法是一种贪心算法,用于求解加权无向图的最小生成树。
-
具体实现过程为:
将所有边按照权值从小到大排序,然后依次加入到生成树中,如果加入该边不会形成环,则加入该边。直到生成树中有n-1条边或者所有边都已经加入。
-
并查集来判断是否形成环:
每个节点初始时都是一个独立的集合,每次加入一条边时,判断该边的两个端点是否在同一个集合中,如果不在,则将两个集合合并。最后判断起点和终点是否在同一个集合中,如果在,则输出当前边的权值,即为最小生成树的权值。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,s,t,fa[20001],o1,o2,o3;
int find(int x){
if(fa[x]==x) return x;
else return find(fa[x]);
}
struct node{
int u,v,w;
}edge[20001];
bool cmp(node a,node b){
return a.w<b.w;
}
int main(){
cin>>n>>m>>s>>t;
for(int i=1;i<=m;i++){
cin>>o1>>o2>>o3;
edge[i]={o1,o2,o3};
}
sort(edge+1,edge+m+1,cmp);//将边权从小到大排序
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
int fx=find(edge[i].u);
int fy=find(edge[i].v);
if(fx!=fy){//并查集判断是否在同一集合中
fa[fx]=fy;//合并
}
if(find(s)==find(t)){
cout<<edge[i].w<<endl;//输出最大权值
return 0;
}
}
return 0;
}