prim
链接: acwing上一个关于prim很好的题解
prim 算法干的事情是:给定一个无向图,在图中选择若干条边把图的所有节点连起来。要求边长之和最小。在图论中,叫做求最小生成树。
prim 算法采用的是一种贪心的策略。
每次将离连通部分的最近的点和点对应的边加入的连通部分,连通部分逐渐扩大,最后将整个图连通起来,并且边长之和最小。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510;
int g[N][N];
int st[N];
int pre[N];
int dist[N];
int n, m;
void prim()
{
int res = 0;
memset(dist, 0x3f, sizeof dist);
memset(pre, -1, sizeof pre);
dist[1] = 0;
for (int i = 0; i < n; i ++ )
{
int t = -1;
for (int j = 1; j <= n; j ++ )
{
if (!st[j] && (t == -1 || dist[j] < dist[t]))
{
t = j;
}
}
if(dist[t] == 0x3f3f3f3f)
{
cout << "impossible";
return;
}
st[t] = 1;
res += dist[t];
for (int i = 1; i <= n; i ++ )
{
if (!st[i] && dist[i] > g[t][i])
{
dist[i] = g[t][i];
pre[i] = t;
}
}
}
cout << res;
}
int main()
{
memset(g, 0x3f, sizeof(g));
cin >> n >> m;
while (m -- )
{
int a, b, c;
cin >> a >> b >> c;
g[b][a] = g[a][b] = min(g[a][b], c);
}
prim();
return 0;
}
优化:
上面代码的时间复杂度为 O(n^2)。
与Dijkstra类似,Prim算法也可以用堆优化,优先队列代替for循环查找距离生成树中最短距离的节点。
优化的Prim算法时间复杂度O(mlogn)。适用于稀疏图,但是稀疏图的时候求最小生成树,Kruskal 算法更加实用。(因为kruskal算法是遍历边,每次找图里面不在生成树中最短的边)
kruskal
算法思路:
-
将所有边按照权值的大小进行升序排序,然后从小到大一一判断。
-
如果这个边与之前选择的所有边不会组成回路,就选择这条边分;反之,舍去。
-
直到具有 n 个顶点的连通网筛选出来 n-1 条边为止。
-
筛选出来的边和所有的顶点构成此连通网的最小生成树。
-
判断是否会产生回路的方法为:使用并查集。
-
在初始状态下给各个个顶点在不同的集合中。、
-
遍历过程的每条边,判断这两个顶点的是否在一个集合中。
-
如果边上的这两个顶点在一个集合中,说明两个顶点已经连通,这条边不要。如果不在一个集合中,则要这条边。
可以发现kruskal遍历的是一条一条边,因此只要将图的所有边存下来就行了
也正是因此,kruskal比较适合找出稀疏图的最小生成树
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int p[N];
struct E{
int a;
int b;
int w;
bool operator < (const E& rhs){
return this->w < rhs.w;
}
}edg[N * 2];
int res = 0;
int n, m;
int cnt = 0;
int find(int a){
if(p[a] != a) p[a] = find(p[a]);
return p[a];
}
void kruskal(){
for(int i = 0; i < m; i++)
{
int pa = find(edg[i].a);
int pb = find(edg[i].b);
if(pa != pb){
res += edg[i].w;
p[pa] = pb;
cnt ++;
}
}
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++) p[i] = i;
for(int i = 0; i < m; i++){
int a, b , c;
cin >> a >> b >>c;
edg[i] = {a, b, c};
}
sort(edg , edg + m );
kruskal();
if(cnt < n - 1){
cout<< "impossible";
}
else cout << res;
return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)