DESCRIPTION
这个地区可以看作是一个无向图,N个点M条边组成。每个边有一个边权。我们定义一条路径的花费,就是这条路径上最大的边权。
现在有一条咸鱼,想从S走到T,徒步旅行。
咸鱼于是找到了你,想让你告诉他从S到T的最小花费。
INPUT
第一行两个整数,N,M。满足(1 <= N <= 10^5, 0 <= M <= 5*10^5)接下来M行,每行三个整数U,V,C。表示有一个连接U点和V点的边,且边权是C。(1<=C<=10^9)接下来一个行是两个整数S,T(1<=S,T<=n)
OUTPUT
输出答案,如果S不能到达T,输出-1
SAMPLE INPUT
5 5
1 2 1
2 3 1
3 4 1
4 5 1
5 1 1
1 3
SAMPLE OUTPUT
1
SOLUTION
比赛的时候用最短路跑了一遍,没过,但是我辉神用最短路过了。。还是我辉神厉害,我呢,只能照着题解来了一波(最小生成树+bfs)。
首先考虑最小生成树,由于prim算法的本质是已经生成最小树的集合与没生成最小树的集合之间的最短边加入到生成树里去,所以无法从prim算法得到最小生成树的图,但是,kruskal不同,它是将所有的边从小到大选择,确定这条边,自然可以确定边的两点,所以,可以根据kruskal来获得最小生成树。
然后使用bfs算法,广搜一遍最小生成树,搜到终点t的时候再遍历s-t这条路,选出最大的即可。
然后现在要考虑,存储的最小生成树的数据结构,最小生成树最多有(n-1)条边,那么,使用链式的(vector)是最好的,这样bfs时最多遍历2*(n-1)次,自然不会超时,而如果使用矩阵的话,那就要遍历n*n次了,(被我注释那一段是超时的写法,我知道它会超时,就是想试一下效果怎样)。
最后就是遍历那条边,存储一条边最好的办法就是前缀数组,pre[u]代表的是u这个点的上一个点,在这里我是二维数组,用pre[u][1]存储边权,然后递归求最大值即可。
#include <iostream>
#include <stdio.h>
#include <string.h>
#define siz 100005
#define inf 0x3f3f3f3f3f3f
#include <vector>
#include <queue>
#include <algorithm>
#define LL long long
using namespace std;
int n,m,s,t;
struct qnode{
LL v,c;
qnode(LL _v=0,LL _c=0):v(_v),c(_c){}
bool operator <(const qnode &r)const{
return c<r.c;
}
};
struct Edge{
int u,v;
int w;
bool operator <(const Edge &r)const{
return w<r.w;
}
//Edge(int _v,int _cost):v(_v),w(_cost){}
}E[5*siz];
//vector<int>vec;
//vector<Edge>E[5*siz];
int F[siz],tol,cnt;
vector<Edge>mst[siz];
void addedge(int u,int v,int w){
E[tol].u=u;
E[tol].v=v;
E[tol].w=w;
++tol;
}
bool vis[siz];
int pre[siz][2];
int findfa(int x){
if(F[x]==x) return x;
else return F[x]=findfa(F[x]);
}
void kruskal(int n){
for(int i=1;i<=n;i++){
F[i]=i;
}
sort(E,E+tol);
//int cnt=0;
for(int i=0;i<tol;i++){
int u=E[i].u;
int v=E[i].v;
int w=E[i].w;
int t1=findfa(u);
int t2=findfa(v);
if(t1!=t2){
F[t1]=F[t2];
Edge x;
x.u=u;
x.w=w;
mst[v].push_back(x);
x.u=v;
mst[u].push_back(x);
//mst[cnt].u=u;
//mst[cnt].v=v;
//mst[cnt++].w=w;
}
//if(cnt==n-1) break;
}
}
void bfs(){
queue<int>que;
while(!que.empty())que.pop();
que.push(s);
vis[s]=1;
memset(vis,false,sizeof(vis));
bool flag=false;
while(!que.empty()){
int u=que.front();
que.pop();
if(u==t){
flag=true;
break;
}
vis[u]=true;
for(int i=0;i<mst[u].size();i++){
if(!vis[mst[u][i].u]){
pre[mst[u][i].u][0]=u;
pre[mst[u][i].u][1]=mst[u][i].w;
que.push(mst[u][i].u);
}
}
/*for(int i=0;i<cnt;i++){
if(!vis[mst[i].v]&&mst[i].u==u){
pre[mst[i].v][0]=u;
pre[mst[i].v][1]=mst[i].w;
que.push(mst[i].v);
}else if(!vis[mst[i].u]&&mst[i].v==u){
pre[mst[i].u][0]=u;
pre[mst[i].u][1]=mst[i].w;
que.push(mst[i].u);
}
}*/
}
if(!flag) cout<<-1<<endl;
else{
int maxx=-1;
int u=t;
while(u!=s){
if(pre[u][1]>maxx) maxx=pre[u][1];
u=pre[u][0];
}
cout<<maxx<<endl;
}
}
int main()
{
scanf("%d %d",&n,&m);
int u,v,w;
for(int i=0;i<m;i++){
scanf("%d %d %d",&u,&v,&w);
addedge(u,v,w);
}
scanf("%d %d",&s,&t);
kruskal(n);
bfs();
return 0;
}
/*
6 6
1 2 2
2 3 3
3 4 4
3 5 2
1 5 5
2 4 3
1 5
*/

本文介绍如何使用最小生成树与广度优先搜索(BFS)算法解决寻找两点间最大边权最小路径的问题。通过Kruskal算法构建最小生成树,并采用BFS遍历该树找出起点到终点的路径及其最大边权。
1886

被折叠的 条评论
为什么被折叠?



