最小生成树

最小生成树

最小生成树(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;
}
posted @ 2020-05-31 20:25  樱花小猪  阅读(131)  评论(0编辑  收藏  举报