【最小生成树】Prim算法和Kruskal算法

一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。简单来说就是假如有10个点,你可以用9条线把这10个点连起来,不漏掉任何一个点,然后这9条边的权值最小,就是**最小生成树**了,就是用*小于顶点个数-1的边*,连接所有点,权值最小。

最小生成树可以用kruskal(克鲁斯卡尔)算法或Prim(普里姆)算法求出。 

Prim算法和Kruskal算法都是基于下述性质:如果(u,v)是图中权值最小的边,则最小生成树中必包含此边。Kruskal算法是针对边来说的,而Prime算法是针对顶点的。
分析Prim算法,该算法由两个并列的循环组成,第一个循环次数为vex_num(即顶点的个数n);第二个循环,外层循环的次数为n-1,内层的循环次数为n。所以总体来说,Prim的时间复杂度为O(n2),并且该算法与图中边数的多少无关,所以该算法适合于求边稠密的图的最小生成树。是一种贪心算法 。
Kruskal算法:将图各边按照权值进行排序,之后每次选择一条边,要注意边不能构成回路。

现在只学会了Kruskal算法,Prim还不会,不过只会Kruskal也是可以解决问题的( • ̀ω•́ )✧

这位大牛有讲Prim算法的,可以看一看Prim:http://blog.csdn.net/niushuai666/article/details/6689295

大概框架是:

图中节点的存储
struct edge{
int u,v,w; //边的顶点,权值
}edges[10];
节点权值排序函数
qsort(edges, m, sizeof(edge), cmp)
合并两个节点函数
void merge(int a,int b)

具体一些的代码:还是要用到之前的并查集的知识 并查集:http://blog.csdn.net/rricky_/article/details/76576120

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include<algorithm>
using namespace std;
int parent[10];
int n,m,num,sumWeight;
int i,j;

struct edge{
    int u,v,w; //边的顶点,权值
}edges[10];

//初始化并查集
void UFset(){
    for(i=1; i<=n; i++) parent[i] = -1;
}

//查找i的根
int find(int x)
{
    if(x!=parent[x])
    parent[x]=find(parent[x]);
    else return parent[x];
}
//合并两个元素a,b
void join(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)    
    {
        parent[fx]=fy;
        printf("加入边:%d %d,权值: %d\n", x,y,edges[i].w);
        sumWeight += edges[i].w;
        num ++;
    }
}

void kruskal(){
    sumWeight = 0;
    num = 0;
    int u,v;
    UFset();
    for(i=0; i<m; i++)
    {
        u = edges[i].u;
        v = edges[i].v;
        join(u,v);
        if(num==n-1)
        {
            printf("最小生成树的权值之和为:%d \n", sumWeight);
            break;
        }
    }
}


//比较函数,用户排序
bool cmp(edge a,edge b)
{
    return a.w<b.w;
}

int main() {

    scanf("%d %d", &n, &m);
    for(i=0; i<m; i++){
        scanf("%d %d %d", &edges[i].u,  &edges[i].v,  &edges[i].w);
    }
     sort(edges,edges+m,cmp);
    kruskal();
}
/*
测试数据:
6 10
1 2 6 
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
 */
Prim算法Kruskal算法都是求解图的最小生成树问题的经典算法,它们的思想和实现方法不同,下面是它们的实验小结。 1. Prim算法 Prim算法是一种贪心算法,它从图的某个点开始,逐步扩展生成树,直到生成整个图的最小生成树算法步骤如下: 1.1 选取任意一个点作为起始点,将该点加入生成树中。 1.2 找到与当前生成树相连的边中,权重最小的边,将其连接的点加入生成树中。 1.3 重复步骤1.2,直到生成整个图的最小生成树Prim算法的时间复杂度为O(E log V),其中 E 表示边的数量,V 表示点的数量。Prim算法的优点是实现简单,适用于稠密图;缺点是不适用于稀疏图。 2. Kruskal算法 Kruskal算法也是一种贪心算法,它从图的所有边开始,逐步扩展生成树,直到生成整个图的最小生成树算法步骤如下: 2.1 将图中所有边按照权重从小到大排序。 2.2 依次选择每条边,判断该边的两个端点是否在同一连通块中,如果不在,则将它们合并,并将该边加入生成树中。 2.3 重复步骤2.2,直到生成整个图的最小生成树Kruskal算法的时间复杂度为O(E log E),其中 E 表示边的数量。Kruskal算法的优点是适用于稀疏图;缺点是实现相对复杂。 综上所述,Prim算法Kruskal算法都是求解图的最小生成树问题的有效算法,选择哪种算法主要取决于图的性质算法实现的难易程度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值