方法一:
kruskal 算法:如果裸算法求出的最小生成树的最大边也一定最小,本题关键体现在代码65行
#include<iostream>
#include<algorithm>
using namespace std;
#define N 100005
#define M 200005
int fa[N];
int n,m;
int maxx;
struct Eage{
int u,v,w;
bool operator< (const Eage & t) const{
return w<t.w;
}
}e[M];
void init()
{
for(int i=1;i<=n;i++)
{
fa[i]=i;
}
}
int find(int x)
{
if(fa[x]!=x)
fa[x]=find(fa[x]);
return fa[x];
}
int main()
{
cin>>n>>m;
init();
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
sort(e,e+m);
for(int i=0;i<m;i++)
{
int u=e[i].u;
int v=e[i].v;
int w=e[i].w;
if(find(u)!=find(v))
{
fa[find(u)]=fa[find(v)];//注意是fa[find(u)],不是fa[u]
maxx=max(maxx,w);
if(find(1)==find(n)) //如果1到n已经连通,退出循环
break;
}
}
cout<<maxx;
return 0;
}
方法二:
思路:二分+bfs(因为用二分就与边权无关了,也可用其他求最短路径算法)
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
#define N 100005
#define M 400005 //无向图边数记得为二倍
int n,m;
struct Eage{
int v;
int w;
}e[M];
int h[N];
int ne[M];
int idx;
int vis[N];
int dis[N];
void add(int u,int v,int w)
{
e[idx].w=w;
e[idx].v=v;
ne[idx]=h[u];
h[u]=idx++;
}
int get(int maxx) //边权大于maxx的边被忽略
{
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
queue<int> qq;
qq.push(1);
vis[1]=1;
dis[1]=0;
while(!qq.empty())
{
int tt=qq.front();
qq.pop();
if(tt==n)
return 1;
for(int i=h[tt];~i;i=ne[i])
{
int v=e[i].v;
int w=e[i].w;
if(w>maxx)
continue;
if(!vis[v])
{
dis[v]=dis[tt]+1;
qq.push(v);
vis[v]=1;
}
}
}
return 0;
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof(h));
int ll=1;
int maxx=0;
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
maxx=max(maxx,w);
add(u,v,w);
add(v,u,w);
}
maxx+=1;
int rr=maxx;
while(ll<rr) //二分找 构成1到n连通图最大边最小
{
int mid=(ll+rr)>>1;
if(get(mid))
rr=mid;
else ll=mid+1;
}
cout<<ll;
return 0;
}