最小生成树

在连通图中求最小生成树的两个算法讲解可以在b站上搜索视频讲解。
kruskal算法适用稀疏图
prim适用稠密图

kruskal算法模板题:

/*
最小生成树的kruskal算法

res最小生成树中的而权重之和
cnt当前价了多少条边
1、将所有边按权重排序O(mlogm)
2、枚举每条边(并查集应用)
3、需要重载< 
*/ 
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010,M=200010,INF=0x3f3f3f3f;

int n,m;
int p[N];
struct Edge{
	int u,v,w;
	
	bool operator < (const Edge&T)const{
	return w<T.w;
	}
}edges[M];

int find(int x){
	if(p[x]!=x) p[x]=find(p[x]);
	return p[x];
} 

int kruskal(){
	sort(edges,edges+m);
	for(int i=1;i<=n;i++)//初始化并查集 
		p[i]=i;
		
	int res=0,cnt=0;//res最小生成树中的权重之和  cnt当前增加了多少条边 
	for(int i=0;i<m;i++){
		Edge t =edges[i];
		t.u=find(t.u),t.v=find(t.v);
		if(t.u!=t.v){
			p[t.u]=t.v;
			res+=t.w;
			cnt++;
		} 
	}
	
	if(cnt<n-1) return INF;
	return res; 
}
int main(){
	cin>>n>>m;
	int u,v,w;
	
	for(int i=0;i<m;i++){
		cin>>u>>v>>w;
		edges[i]={u,v,w};
	}
	//注意读入的是m
	int x=kruskal();
	if(x>INF/2) cout<<"impossible\n";
	else
		cout<<x<<endl;
	return 0; 
} 

prim算法模板:

输入
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
输出
6

/*
S:当前已经在联通块中的所有点的集合
1. dist[i] = inf
2. for n 次
    t<-S外离S最近的点
    利用t更新S外点到S的距离
    st[t] = true
n次迭代之后所有点都已加入到S中
联系:Dijkstra算法是更新到起始点的距离,Prim是更新到集合S的距离
*/
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;

int n, m;//n个点  m条边 
int g[N][N];//邻接矩阵,存储所有边
int dist[N];//存储其他点到最小生成树中的距离
bool st[N];//存储每个点是否已经在生成树中 
//如果图不连通,则返回INF,否则返回最小生成树的树边权重之和 
int prim() {
    memset(dist, INF, sizeof dist);
    int res = 0;

    for(int i = 0; i < n; i++) {
        int t = -1;
        //寻找离集合S最近的点   
        for(int j = 1; j <= n; j++) 
            if(!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        //判断是否连通,有无最小生成树
        if(i && dist[t] == INF) 
			return INF;
        if(i) 
			res += dist[t];
        st[t] = true;
        //更新最新S的权值和
        for(int j = 1; j <= n; j++) 
			dist[j] = min(dist[j], g[t][j]);
    }

    return res;
}

int main() {
    cin >> n >> m;
    int u, v, w;

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            if(i ==j) g[i][j] = 0;
            else g[i][j] = INF;

    while(m--) {
        cin >> u >> v >> w;
        g[u][v] = g[v][u] = min(g[u][v], w);
    }
    int t = prim();
    //临时存储防止执行两次函数导致最后仅返回0
    if(t == INF) cout<<("impossible\n");
    else cout << t << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值