关于图的最小生成路径——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 ;
}
如有问题,欢迎大家指正~