题目条件:
给定一个 个点 条边的无向图图中可能存在重边和自环,边权可能为负数。
最小生成树:通过所给的边,将所有节点相连接,并且没有自环。
题目要求返回最小生成树边权之和。
算法流程:
1> 初始化:定义邻接矩阵 存储边和权重, 为 节点到集合的距离(集合含义:构成最小生成树的节点所构成的点集,该集合在遍历节点过程中逐渐将节点添加到集合中。)
memset(g,0x3f,sizeof g);
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
最开始时候,可以定义所有边长为无穷大,节点到集合距离为无穷大。(定义1节点到集合距离为0)
2> 最小生成树包含所有节点,所以要经过n次遍历,将n个节点放到集合当中
3> 遍历集合外的节点,找到集合外节点到集合距离最小的那个节点,并将这个节点放到集合中,在答案中加上这个最小距离。(这里要判断,如果我们找到的点到集合的距离Wie无穷大,则意味着这个节点没有与其他节点相连接,不存在最小生成树)
4> 集合中添加新的节点后,更新集合外的点到集合的距离。
重复操作上述过程,最后范围答案。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 510;
const int INF = 0x3f3f3f3f;
int g[N][N],dist[N];
int n,m;
int res;
bool st[N];//用于判断该点是否在集合中
bool prime(){
memset(dist,0x3f,sizeof dist);
dist[1] = 0;//初始化第一个节点方便进行算法
res = 0; //将结果值为零
for(int i = 0;i < n;i++){ //算法要求进行n次迭代,将n个点加入到集合中
int t = -1; //用于存储最小距离节点,当我们不知道用哪个点进行切入就设置t = -1;
for(int j = 1;j <= n;j++){
if(!st[j] && (t == -1 || dist[t] > dist[j])) t = j;
//如果j节点不在集合中,并且节点t到集合的距离要大于当前遍历到的节点j的距离,则更新t;
}
if(dist[t] > INF / 2) return false;
//如果我们发现最小距离是无穷大,则不存在最小生成树
st[t] = true;
//否则,我们找到了最小距离节点t,并将t放到集合中
res += dist[t];
//在记录最小生成树边权之和的变量中加上这个最小距离
for(int j = 1;j <= n;j++){ //边所有节点
if(!st[j]) dist[j] = min(dist[j],g[t][j]);
//如果这个节点不在集合中,则更新这个点到集合的距离
}
}
return true;
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
cin >> n >> m;
memset(g,0x3f,sizeof g);
while(m--){
int a,b,c;
cin >> a >> b >> c;
g[a][b] = g[b][a] = min(g[a][b],c);
}
if(prime()) cout << res << endl;
else cout << "impossible" << endl;
return 0;
}
大家一定要牢记这些算法模板!!!~~~~!!!
祝大家学好算法,有什么问题欢迎问我~