学习本算法之前,先来回顾一下Dijistra算法的核心:用一个数组dis来记录源点到各个顶点的距离,然后每次扫描dis数组,从中选择出离源点最近的顶点,看通过该顶点为始点的边能否更新源点到其他各个顶点的距离。
这里我们对这个方法稍稍改变一下,便能得到prim算法的核心。在这里用dis数组记录生成树中到各个顶点的最短距离,也就是说现在的最短距离不是到源点的最短距离,而是到已经被选入生成树中顶点的最短距离,即如果选取点t加入生成树,
dis[k] > e[t][k],那么dis更新为e[t][k],而不是dis[k]+e[t][k]。
明白核心之后,我们便可以随便选择一个点加入最小生成树,因为最小生成树肯定包含图中所有的点的,然后更新dis中到生成树的最小距离,然后再选出最短的一个dis[i],然后看通过i点是否能更新生成树的到其余顶点的距离,然后重复操作,直至选择出n个点为止,算法结束。
#include <iostream>
#include <cstdio>
#define inf 11111
using namespace std;
struct note{
int b, w, next;
} edge[105];
int head[105], book[105], no, dis[105];
void init(int n){
int i;
for(i = 1; i <= n; ++i){
book[i] = 0;
head[i] = -1;
}
}
void add(int a, int b, int w){
edge[no].b = b;
edge[no].w = w;
edge[no].next = head[a];
head[a] = no++;
}
int main(){
int n, m, k, ans, ct, a, b, c, i, min, l;
while(cin >> n >> m){
init(n);
no = 1;
for(i = 1; i <= m; ++i){
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
for(i = 1; i <= n; ++i)
dis[i] = inf;
k = head[1];
book[1] = 1;
while(k != -1){
if(!book[edge[k].b] && dis[edge[k].b] > edge[k].w)
dis[edge[k].b] = edge[k].w;
k = edge[k].next;
}
ct = 1;
while(ct < n){
min = inf+1;
for(i = 1; i <= n; ++i){
if(!book[i] && min > dis[i]){
min = dis[i];
l = i;
}
}
++ct;
book[l] = 1;
ans += dis[l];
k = head[l];
while(k != -1){
if(!book[edge[k].b] && dis[edge[k].b] > edge[k].w)
dis[edge[k].b] = edge[k].w;
k = edge[k].next;
}
}
printf("%d\n", ans);
}
return 0;
}
由堆优化的Dijistra算法,我们也会想能否通过堆来优化prim算法呢,其实是可以的,上代码。
#include <iostream>
#include <cstdio>
#include <queue>
#define inf 11111
using namespace std;
struct node{
int b,w;
node(int b, int w){
this->b = b;
this->w = w;
}
bool operator<(node n) const{
return this->w > n.w;
}
};
struct note{
int b, w, next;
} edge[105];
int head[105], book[105], no, dis[105];
void init(int n){
int i;
for(i = 1; i <= n; ++i){
dis[i] = inf;
book[i] = 0;
head[i] = -1;
}
}
void add(int a, int b, int w){
edge[no].b = b;
edge[no].w = w;
edge[no].next = head[a];
head[a] = no++;
}
int main(){
int n, m, k, ans, ct, a, b, c, i;
while(cin >> n >> m){
init(n);
no = 1;
for(i = 1; i <= m; ++i){
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
priority_queue<node> q;
ans = 0;
k = head[1];
while(k != -1){
q.push(node(edge[k].b, edge[k].w));
dis[edge[k].b] = edge[k].w;
k = edge[k].next;
}
ct = 1;
book[1] = 1;
while(ct < n){
node x = q.top();
q.pop();
if(book[x.b]) continue;
book[x.b] = 1;
++ct;
ans += x.w;
k = head[x.b];
while(k != -1){
if(book[edge[k].b] == 0 && dis[edge[k].b] > edge[k].w){
dis[edge[k].b] = edge[k].w;
q.push(node(edge[k].b, edge[k].w));
}
k = edge[k].next;
}
}
printf("%d\n", ans);
}
return 0;
}
继续加油~