题目描述
解题思路
给出n边,m点,求最小消耗,可以套用最小生成树模板来做
最小生成树主要可以用Prim和Kruskal解决
- Prim时间复杂度是O(n2),n是顶点数量,和边数量无关,主要用于稠密图
- Kruskal时间复杂度是O(eloge),e是边数量,和顶点数量无关,主要用于稀疏图
- Kruskal的核心操作在于查并集,而且是对边进行的操作
- 查并集可见我上篇博客中的练习题LeetCode:Friend Circles 查并集
- Kruskal依次选出边长最小的,判断边上两点是不是同一个集合(find),如果不是,则连到一个集合中去(union),终止条件是集合中:边数=顶点数-1,说明是一个最小生成树
代码
本题中输入是邻接表
可套作kruskal模板(但也不全适用,目前比较精简)
#include <iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
#define max 111
struct node{//边
int u,v,w;
}edge[max];
int n,m,fa[max];
int cmp(node a,node b){
return a.w<b.w;
}
void init(){
for(int i=0;i<m;i++){
fa[i] = i;
}
}
int find(int x){
if(x==fa[x]) {
return x;
}else{
return fa[x]=find(fa[x]);
}
}
void _union(int x,int y){
x = find(x);
y = find(y);
if(x!=y){
fa[y] = x;
}
}
int main() {
freopen("in.txt","r",stdin);
while(1){
int count=0,ans=0;
cin>>n>>m;//n边m点
if(n==0) break;
init();
for(int i=0;i<n;i++){
cin>>edge[i].u>>edge[i].v>>edge[i].w;
}
sort(edge,edge+n,cmp);//边从小到大排序
for(int i=0;i<n;i++){
if(find(edge[i].u)!=find(edge[i].v)){//对边进行操作
_union(edge[i].u,edge[i].v);
count++;
ans+=edge[i].w;//这里根据题意写
}
}
if(count==m-1){
cout<<ans<<endl;
}else{
cout<<"?"<<endl;
}
}
fclose(stdin);
return 0;
}