最小生成树
最小生成树
最小生成树(MST)是属于图论中的一种算法,主要用于解决最短路径,最小费用等问题
目前有两种算法可以从一个加权图中找出最小生成树:
首先是Prime算法,这种算法可以在加权图中找到一棵生成总费用(距离)最小的树
即每个节点与父节点和子节点是最小(短)的。
但这种算法每次需要遍历图中所有节点来确定父节点,然后遍历可用节点为子节点,故算法复杂度为O(V^2)
还有一种算法为Dijkstra算法,它主要解决单源的最短路径(费用)等问题,
因为每个节点中存储的是离给定节点的最小(最少)距离(费用)。
这两种算法均不能解决负权值的图。
下面是这两种算法的C++具体实现,造好轮子以备不时之需。
代码
#include <iostream>
using namespace std;
//WHITE代表节点未访问,GRAY代表节点正在访问,BLACK代表节点已经访问
const int WHITE = 0;
const int GRAY = 1;
const int BLACK = 2;
//定义一个比所有权值都大的数,作为无穷大
const int INFTY = (1<<10);
const int MAX = 25;
int M[MAX][MAX];
//N表示图的节点数目, s表示 dijkstra 算法中的起始点
int N, s;
//primes算法
int prim(){
//u为当前访问的父节点
//d[i]表示第i个节点的所有边中,权值最小的边
//p[i]表示MST中节点i的父节点
int mincost, u;
int d[MAX], p[MAX], color[MAX];
//初始化
for (int i=0; i<N; i++){
d[i] = INFTY; p[i] = -1; color[i] = WHITE;
}
d[0] = 0;
while (true){
mincost = INFTY; u = -1;
//搜索当前父节点
for (int i=0; i<N; i++){
if (mincost>d[i] && color[i]!=BLACK){
u = i; mincost = d[i];
}
}
if (u==-1) break;
color[u] = BLACK;
//对当前父节点搜索子节点,并更新权值
for (int v=0; v<N; v++){
if (color[v]!=BLACK && M[u][v]!=INFTY){
if (d[v]>M[u][v]){
d[v] = M[u][v];
p[v] = u;
color[v] = GRAY;
}
}
}
}
int sum = 0;
//打印MST总和
for (int i=0; i<N; i++){
if (p[i]!=-1) sum+=M[i][p[i]];
}
return sum;
}
void dijkstra(){
int mincost;
//与prim算法不同,d[i]表示起点s到i的最短路径
int d[MAX], color[MAX];
for(int i=0; i<N; i++){
d[i] = INFTY;
color[i] = WHITE;
}
d[s-1] = 0;
color[s-1] = GRAY;
while (true){
mincost = INFTY;
int u = -1;
for (int i=0; i<N; i++){
if (mincost>d[i] && color[i] != BLACK){
u = i;
mincost = d[i];
}
}
if (u==-1) break;
color[u] = BLACK;
for (int v=0; v<N; v++){
if (color[v]!=BLACK && M[u][v]!=INFTY){
int dis = M[u][v] + d[u];
if (d[v]>dis){
d[v] = dis;
color[v] = GRAY;
}
}
}
}
//打印所有节点与起点s的联通情况,如果不连通打印-1,否则打印最短距离
for (int i=0; i<N; i++){
cout<<i<<" "<<(d[i]==INFTY?-1:d[i])<<endl;
}
}
int main(){
cin>>N;
for (int i=0; i<N; i++){
for(int j=0; j<N; j++){
M[i][j] = INFTY;
}
}
//输入初始图G的邻接矩阵
/*
for (int i=0; i<N; i++){
for(int j=0; j<N; j++){
int x;
cin>>x;
M[i][j] = x;
}
}
*/
cin>>s;
cout<<prim()<<endl;
dijkstra();
return 0;
}