Prim求最小生成树
\(Prim\)也挺简单的。我们来看一下具体思路
1.初始化\(dis\)距离数组为极大值。
2.迭代所有结点。
3.定义点\(t\),用\(t\)来找到集合外距离最小的点,每次如果这个点不在集合里并且\(t\)还是初始值,或者\(dist_t>dist_j\),就更新\(t\)的点。
4.特判,更新最小生成树的权值,然后用点\(t\)更新,其他点和集合的距离,将点\(t\)放入最小生成树。
是不是很像\(dij\)算法(迪杰斯特拉)?没错差距就只有一处,那就是一个是更新到起点的距离,一个是更新的到集合的距离,那什么是到集合的距离呢?
很简单,假设有一个点到集合有\(x\)条边,那其中最短的边就是到集合的距离。
时间复杂度\(O(n^2)\),相较于\(Kruskal\)慢了很多,但毕竟他还能存哪些节点是最小生成树的,还可以吧。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
int n,m;
int g[N][N],dis[N];
bool st[N];//表示点是否在集合当中
int prim()
{
memset(dis,0x3f,sizeof(dis));
int res = 0;//最小生成树的边权值和
for (int i = 0; i < n; i ++ )
{
int t = -1;
for (int j = 1; j <= n; j ++ )//找到集合外距离最小的点
{
if(!st[j] && (t == -1 || dis[t] > dis[j]))
t = j;
}
if(i && dis[t] == INF) return INF;
if(i) res += dis[t];//如果不是第一个点,那么就把这个点用那条边和集合连起来
for (int j = 1; j <= n; j ++ )
dis[j] = min(dis[j],g[t][j]);
st[t] = true;
}
return res;
}
int main()
{
scanf("%d%d", &n, &m);
memset(g,0x3f,sizeof(g));
while (m -- )
{
int a,b,c;
scanf("%d%d%d", &a, &b, &c);
g[a][b] = g[b][a] = min(g[a][b],c);//无向图
}
int t = prim();
if(t == INF) puts("impossible");
else printf("%d\n",t);
return 0;
}

浙公网安备 33010602011771号