关于图的最小生成路径——Kruskal算法和Prime算法

关于图的最小生成路径——Kruskal算法和Prime算法

写博客其实就是为了回顾所学的~现在学起这些东西都更轻松了…


/**
	Kruskal算法:关键三步——1、排序;2、判断循环条件;3、找符合要求的边;
 	关键:用到了并查集;
 **/


#include<iostream>
using namespace std ;
const int Max_Size = 100 ;
const int  INFINITY = 65535 ;
int n,e;

typedef struct ENode{
    int v1,v2 ;
    int w ;
}ENode;
ENode E[Max_Size];

int Father[Max_Size];

void Create(){//建图
    cin >> n >> e ;
    for(int i = 0 ;i<e;i++){
        cin >> E[i].v1 >> E[i].v2 >> E[i].w;
    }
}
bool cmp(ENode &a,ENode &b){
    return a.w < b.w;
}

int Find_Father(int x ){//并查集(其实就是找到各个节点的根节点,然后压缩路径)
    int a = x ;
    while (x != Father[x]){//回溯找到根节点
        x = Father[x] ;
    }
    while (a != Father[a]){//压缩路径
        int z = a ;
        a = Father[a];
        Father[z] = x ;
    }
    return x ;
}

int sum = 0 ;
int Kruskal(){
    int num = 0 ;//循环次数(跳出循环的条件二:边数 = 节点数-1——树的性质)
    for(int i = 0 ;i<n ; i++ ){//初始化,将各节点的根节点置为自身
        Father[i] = i ;
    }
    
    sort(E,E+e,cmp);
    
    for(int i = 0 ;i<e ;i++){//对边操作,所以小于边数
        int fa_v1 = Find_Father(E[i].v1);
        int fa_v2 = Find_Father(E[i].v2);
        
        if(fa_v1 != fa_v2){//在不同的连通块(根节点不一样)
            Father[fa_v1] = fa_v2;  //加入并查集
            sum += E[i].w;  //权值累加
            num ++ ;
            if(num == n -1){
                break ;
            }
        }
        
    }
    if(num != n-1){//不等于,则代表图不连通,此时树肯定也不连通
        return -1 ;
    }
    
    return sum ;
}

int main (){
    Create();
    cout<<"最小路径为:" << Kruskal() << endl ;
    
    return 0 ;
}

下面是关于Prime算法(个人觉得可以跟Dijkstra一起学)


/**
 prime算法与Dijkstra差不多,唯一不同的就是
 prime算法是最小路径,计算过程是集合与新的节点来比较距离;
 而Dijkstra是点与点来比较距离;
 
 **/


#include<iostream>
using namespace std ;
const int Max_Size = 100 ;
const int  INFINITY = 65535 ;
int n,e;

int Visited[Max_Size];
int Dis[Max_Size];          //新节点与集合的距离
int G[Max_Size][Max_Size];

void Create(){
    cin >> n >> e ;
    for(int i = 0 ;i<n ;i++ ){//初始化图
        for(int j = 0 ;j< n ;j++ ){
            if(i == j){
                G[i][j] = 0 ;
            }else {
                G[i][j] = INFINITY;
            }
        }
    }
    
    for(int i = 0;i<e;i++){
        int v1,v2,w;//边的两个端点,权值
        cin >> v1 >> v2 >> w ;
        G[v1][v2] = w ;
        G[v2][v1] = w ;
    }
}
int sum = 0 ;
int Prime(){
    fill(Dis, Dis+Max_Size, INFINITY);//用fill不用memset的原因,后者赋值大数会出问题
    memset(Visited, 0, sizeof(Visited));
    Dis[0] = 0 ;//规定起始节点(无所谓哪个)
    
    for(int i =0 ;i< n ;i++){//对节点操作,所以是小于n
        
        int u = -1 ,min = INFINITY ;
        for(int j = 0 ;j< n;j++ ){//同Dijkstra,找最短
            if(Visited[j] == 0 && Dis[j] < min ){
                u = j ;
                min = Dis[j];
            }
        }
        if(u == -1 )    {
            sum = -1 ;
            return -1;
        }
        Visited[u] = 1 ;
        sum += Dis[u];//相当于将u加入到集合了
        
        for(int j = 0 ;j< n ;j++ ){
            if(Visited[j] == 0  && G[u][j] < Dis[j]){//这里判断条件,跟Dijkstra也不一样,这儿是点到集合的距离
                Dis[j] = G[u][j];
            }
        }
        
    }
    
    return sum ;
}

int main (){
    Create();
    cout<<"最小路径为:" << Prime() << endl ;
    
    return 0 ;
}

如有问题,欢迎大家指正~

©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页