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;
}