并查集+kruskal P1111 修复公路
题目求最早什么时候任意两个村庄能够通车,将每个村庄看成一个顶点,只要找到这些顶点构成的最小生成树,就可找到通车的最小代价。
kruskal算法求最小生成树,每次选择权最小的边,并且所有选择的边不能形成环,直到找到n-1条边将n个点连接起来,构成最小生成树。
上述中使选择的边不能形成环,可以通过并查集得到。
并查集:
初始化:令p[i]=i,即每个点单独为一个集合。
并:若存在一个一条路i->j,那么令p[dsu( p[i] )]=dsu(p[j]);
差:int dsu(int x){return p[x]==x ?x: p[x]=dsu(p[x]); }
#include<bits/stdc++.h>
using namespace std;
#define N 1010
#define M 100010
int n,m;
int p[N];//集合
int T=0;
struct way{
int x,y,t;
}c[M];//x y路连接的村庄,t修路花的时间
bool cmp(way a,way b){
return a.t<b.t;
}
int dsu(int x){
return p[x]==x ?x: p[x]=dsu(p[x]);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].t);
}
sort(c+1,c+m+1,cmp);//按时间从短到长排序
for(int i=1;i<=n;i++){
p[i]=i;//每个村庄为一个独立的集合
}
for(int i=1;i<=m;i++){
int x=dsu(c[i].x),y=dsu(c[i].y);
if(x!=y){//x y不在同一个集合,即x->y无路
p[x]=y;//x y为同一个集合
n--;//找到一条路,总共找n-1条路
}
if(n==1){
cout<<c[i].t<<endl;
return 0;
}
}
cout<<-1<<endl;
return 0;
}