最小生成树prim算法板子

最小生成树,也就是求图里面用n-1条边使得整个图连接起来的算法。
两种算法,一种是kusual, 另一种是prim。
两种算法都很简单。
kusual : 简单来说就是我们先把所有的边排序,然后从小到大选出n-1条边使得图相连。
那么就是用优先队列维护最小,用并查集维护是否在同一个集合就好。
prim:主要思想和迪杰斯特拉是一样的,每次找最小的,没有被找到过的那一个边对应的点,然后用这个点去更新其余边的最小值。只是这里记录的是最短路里面上一个点到当前点的值。 证明麻烦得很,总之应该是贪心。
总之前人发明的东西真强啊。
这里用的是邻接矩阵存图,也可以用vector 或 链式前项星等方式,思想是一样的,不过是遍历方式换了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5010;
int dist[N], vis[N], n, m;
const long long inf = 9 * 1e18;
int G[N][N];

int prim(){
	for(int i = 1; i <= n; i++){
		dist[i] = inf; vis[i] = 0;
	}
	for(int i = 2; i <= n; i++){
		dist[i] = min(dist[i], G[1][i]);
	}
	int ans = 0; vis[1] = 1;
	for(int i = 1; i < n; i++){
		int now = -1, mn = inf;
		for(int i = 1; i <= n; i++){
			if(!vis[i] && dist[i] < mn){
				mn = dist[i];
				now = i;
			}
		}
		if(now == -1) return -1; 
		ans += mn;
		vis[now] = 1;
		
		for(int i = 1; i <= n; i++){
			if(!vis[i]){
				dist[i] = min(dist[i], G[now][i]);
			}
		}
	}
	
	return ans;
}



signed main(){
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	memset(G, 0x3f, sizeof(G));
	cin >> n >> m;
	for(int i = 1; i <= m; i++){
		int u, v, w;
		cin >> u >> v >> w;
		G[u][v] = G[v][u] = w;
	}
	int ans = prim();
	if(ans == -1){
		cout << "no ansers\n";
	}else{
		cout << ans << endl;
	}
}

#include<bits/stdc++.h>
using namespace std;
const int N = 5010;
const long long inf = 9 * 1e18;
#define int long long
int n, m, dist[N], vis[N];

int G[N][N];

inline void add(int from, int to, int w){
	G[from][to] = G[to][from] = w;
}

struct bb{
	int dist, id;
	bool operator < (const bb f) const{
		return f.dist < dist;
	}
};

//priority_queue<bb> q;
int prim(){
	priority_queue<bb> q;
	for(int i = 1; i <= n; i++){
		dist[i] = inf; vis[i] = 0;
	}
	int ans = 0;
	q.push({0, 1});
    int cot = 0;
	while(!q.empty()){
		bb now = q.top();
		q.pop();
		if(vis[now.id]) continue;
		vis[now.id] = 1;
		ans += now.dist ; cot++;
		if(cot == n) break;
		for(int i = 1; i <= n; i++){
			
		    if(!vis[i] && G[now.id][i] < dist[i]){
		    	dist[i] = G[now.id][i];
		    	q.push({dist[i], i}); 
			}
		}
	}
//	while(!q.empty()) q.pop();
	if(cot < n) return -1;
	return ans;
}



signed main(){
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	memset(G, 0x3f, sizeof(G));
	cin >> n >> m;
	for(int i = 1; i <= m; i++){
		int u, v, w;
		cin >> u >> v >> w;
		add(u, v, w); add(v, u, w);
	}
	int ans = prim();
	cout << ans << endl;
}

代码思路就是这样,不断找最小的维护,一个是直接遍历,一个是优先队列维护最小。说实话,已经很简洁了。但是要注意的是优先队列的创建位置,要依据情况也就是数据大小决定。(放在里面肯定快)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值