<h1>题目大意</h1>
给定一个图,求瓶颈最短路(及求出一条是该路径最大值最小的路径)。
<h1>解题报告</h1>
<h2>方法一</h2>
注意最大值最小,我们立马想到了二分。
实际上,由于这道题拥挤度的范围不大,可以二分。
二分的区间就在边权最小值与最大值之间。
我们使用bfs来检查答案。每次 bfs 时验证只通过边权不超过的值来判断答案是否可行。
具体代码如下。
#include <iostream>
#include <cstring>
#include <climits>
#include <cstdio>
#include <queue>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
const int MAXN = 10000 + 5;
const int MAXM = 2 * MAXN + 5;
int N,M,S,T;
struct Node{
struct Edge *firstEdge;
bool vis;
}node[MAXN];
struct Edge{
Node s,t;
int w;
Edge *next;
}pool[MAXM 2],frog = pool;
Edge New(Node s,Node *t,int w){
Edge *ret = ++frog;
ret->s = s;ret->t = t;
ret->w = w;ret->next = s->firstEdge;
return ret;
}
inline void add(int u,int v,int w){
node[u].firstEdge = New(&node[u],&node[v],w);
node[v].firstEdge = New(&node[v],&node[u],w);
}
bool check(int k){
for(int i = 1;i <= N;i++) node[i].vis = false;
std::queue<Node *> q;
q.push(&node[S]);
while(!q.empty()){
Node *v = q.front();
q.pop();
v->vis = true;
for(Edge *e = v->firstEdge;e;e = e->next){
if(!e->t->vis && e->w <=k){
q.push(e->t);
if(e->t == &node[T]) return true;
}
}
}
return false;
}
int main(){
int L = INT_MAX,R = INT_MIN;
scanf("%d%d%d%d",&N,&M,&S,&T);
for(int u,v,w,i = 1;i <= M;i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
L = std::min(L,w);
R = std::max(R,w);
}
while(L < R){
int mid = (L + R) >> 1;
if(check(mid)) R = mid;
else L = mid + 1;
}
printf("%dn",L);
return 0;
}
<h2>方法二</h2>
我们可以借助于最小生成树的思想,每次我们判断一条边的两个点是否在同一集合,如果不在就合并。
对边进行排序。只需要整体扫一遍。
具体代码如下。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
const int MAXN = 10000 + 5;
const int MAXM = MAXN * 2 + 5;
int N,M,S,T;
int ans;
struct Edge{
int u,v,w;
bool operator < (const Edge &other) const{
return w < other.w;
}
}e[MAXM];
int f[MAXN];
int find(int x){
return x == f[x] ? x : f[x] = find(f[x]);
}
void Kruskal(){
int cnt = 0;
for(int i = 1;i <= M;i++){
int fu = find(e[i].u),fv = find(e[i].v);
if(fu == fv) continue;
++cnt;
if(find(S) == find(T)) break;
//ans = std::max(ans,e[i].w);
ans = e[i].w;
f[fv] = fu;
if(cnt == N - 1) break;
}
}
int main(){
scanf("%d%d%d%d",&N,&M,&S,&T);
for(int i = 1;i <= N;i++) f[i] = i;
for(int i = 1;i <= M;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
std::sort(e + 1,e + M + 1);
Kruskal();
printf("%d",ans);
return 0;
}