这道题还是有点难度的!!!!!!!!

星火燎原  •  3个月前


/ 1.假设树最小边是第i个边(已排序) 2.比它大的到m 3.使用kruscal最长边尽可能小 / //最小边最大,最大边最小

include

include

using namespace std; struct edge{

int a,b;
int len;
bool operator < (edge e2){		//重载运算符 
	return len<e2.len;
}

}list[2000005]; int n,m; int group[100005]; //连通分量看作一组组 group[i]的值表示编号为i的节点属于那个连通分量 int find(int x){ //并查集 查连通分量编号

if(x!=group[x]){		//并不是自己的编号 
	group[x]=find(group[x]);		//去查与自己连通的编号 
}
return group[x];		//相等,返回自身组号 

} int main(){

cin>>n>>m;		//n点m边 
for(int i=0;i<m;i++){
	cin>>list[i].a>>list[i].b>>list[i].len;
} 
//输入 
sort(list,list+m); 
int ans=1000000000;
for(int i=0;i<m-1;i++){		//不断假设i是最小权值边来生成树
	int start=i;		//目前考虑的边的下标 
	for(int j=1;j<=n;j++) group[j]=j;		//初始化并查集 
	for(int j=0;j<n-1;j++){		//选n-1条边出来生成树 
		while(start<m&&find(list[start].a)==find(list[start].b)){	//如果在同一个连通分量 
			start++;		//这条边不能要,跳过 
		}
		if(start==m) break; //如果以i为最小权值边已经不能生成树了,那么i和比i更大的更不能要 
		group[find(list[start].a)]=group[find(list[start].b)];		//合并连通分量编号 
	}
	//以上为建树(36-44) 
	if(start==m) break; 	//如果以i为最小权值边已经不能生成树了,那么i和比i更大的更不能要,上次没切完,这次继续切出 
	ans=min(ans,list[start].len-list[i].len);	//生成树完成后,start的下标就在最大生成树的最大权值边,减去i边的权值,即为所求差 
}
cout<<ans<<endl;
return 0;

}


评论:

请先登录,才能进行评论