最小生成树在一个图中可以有多个,但是如果一个图中边的权值互不相同的话,那么最小生成树只可能存在一个,用反证法很容易就证明出来了。

当然最小生成树也是一个图中包含所有节点的权值和最低的子图。

在一个图中权值最小的那个边一定在最小生成树中,如果一个图包含环,环中权值最大的边一定不在最小生成树中,还有就是连接图的任意两个划分的边中权值最短的那一条一定在最小生成树中。

下面介绍两个算法。

Prim算法

Prim算法就是以任意一个点为源点,将所有点分为两组,一组是已经在最小生成树上的点,另一组是还未在最小生成树上的点,最初只有源点在最小生成树上。图中一定存在这样的边:它们的一个顶点在最小生成树上,另一点不在最小生成树上,将这些边中权值最短的那一条以及所连接的点加入最小生成树,继续循环直至所有点都在最小生成树上为止。在具体实现中,可以用一个包含所有节点的辅助数组来记录,这个数组的每个元素包含该点到最小生成树的距离最短的边的权值和这条边的另一个端点(也就是已经在树上的那个点),如果这个点已经在最小生成树上了,权值就为0,这样每次往最小生成树上新加一个点的时候,就去检查所有与它相邻的点,如果那些相邻的点到新加的的距离小于到原先树中点的距离的话,就更新那些点在辅助数组中的信息。

int Prim(struct Graph *G, struct Vertex vertex_list[ ], int S){
    ;

    ; i < G->vertex_num; i++){
        if(S != i){
            vertex_list[i].adjacent_vertex = S;
            vertex_list[i].low_cost = G->map[S][i];
        }
        else{
            vertex_list[i].adjacent_vertex = -;
            vertex_list[i].low_cost = ;
        }
    }
    ; j < G->vertex_num; j++){
        min_cost = Infinity;
        ; i < G->vertex_num; i++){
             != vertex_list[i].low_cost&&min_cost > vertex_list[i].low_cost){
                min_cost = vertex_list[i].low_cost;
                tmp_index = i;
            }
        }
        sum += min_cost;
        vertex_list[tmp_index].low_cost = ;
        ; i < G->vertex_num; i++){
             != vertex_list[i].low_cost&&vertex_list[i].low_cost > G->map[tmp_index][i]){
                vertex_list[i].adjacent_vertex = tmp_index;
                vertex_list[i].low_cost = G->map[tmp_index][i];
            }
        }
    }

    return sum;
}

Kruskal算法

Kruskal算法就是将所有边按权值从小到大加入最小生成树中,并且保证不形成环,确定不形成环的方式类似于并查集。

int Kruskal(struct Graph *G){
    , i, j, sum = , tmp, tmp_1, tmp_2;
    int vertex_list[G->vertex_num];
    struct Edge edge_list[G->edge_num];

    ; i < G->vertex_num; i++){
        vertex_list[i] = i;
    }
    ; i < G->vertex_num; i++){
        for(j = i; j < G->vertex_num; j++){
            if(Infinity != G->map[i][j]){
                edge_list[index].start = i;
                edge_list[index].end = j;
                edge_list[index].weight = G->map[i][j];
                index++;
            }
        }
    }
    qsort(edge_list, G->edge_num, sizeof(struct Edge), comp);
    ; i < G->edge_num; i++){
        if(vertex_list[edge_list[i].start] != vertex_list[edge_list[i].end]){
            ; j < G->vertex_num; j++){
                if(vertex_list[j] == vertex_list[edge_list[i].end]){
                    vertex_list[j] = vertex_list[edge_list[i].start];
                }
            }

            sum += edge_list[i].weight;
            printf("%d %d\n", edge_list[i].start, edge_list[i].end);
        }
    }

    return sum;
}

下面是完整代码,我也没怎么测过。

//
//  main.c
//  Minimum Spanning Tree
//
//  Created by 余南龙 on 2016/11/27.
//  Copyright © 2016年 余南龙. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>

#define MAXV 100
#define Infinity 10000000

struct Vertex{
    int adjacent_vertex;
    int low_cost;
};

struct Edge{
    int start;
    int end;
    int weight;
};

struct Graph{
    int map[MAXV][MAXV];
    int edge_num;
    int vertex_num;
};

int comp(const void *a, const void *b){
    struct Edge *pa = (struct Edge *)a;
    struct Edge *pb = (struct Edge *)b;
    if(pa->weight < pb->weight){
        ;
    }
    else{
        ;
    }
}

int Prim(struct Graph *G, struct Vertex vertex_list[ ], int S){
    ;

    ; i < G->vertex_num; i++){
        if(S != i){
            vertex_list[i].adjacent_vertex = S;
            vertex_list[i].low_cost = G->map[S][i];
        }
        else{
            vertex_list[i].adjacent_vertex = -;
            vertex_list[i].low_cost = ;
        }
    }
    ; j < G->vertex_num; j++){
        min_cost = Infinity;
        ; i < G->vertex_num; i++){
             != vertex_list[i].low_cost&&min_cost > vertex_list[i].low_cost){
                min_cost = vertex_list[i].low_cost;
                tmp_index = i;
            }
        }
        sum += min_cost;
        vertex_list[tmp_index].low_cost = ;
        ; i < G->vertex_num; i++){
             != vertex_list[i].low_cost&&vertex_list[i].low_cost > G->map[tmp_index][i]){
                vertex_list[i].adjacent_vertex = tmp_index;
                vertex_list[i].low_cost = G->map[tmp_index][i];
            }
        }
    }

    return sum;
}

int Kruskal(struct Graph *G){
    , i, j, sum = , tmp, tmp_1, tmp_2;
    int vertex_list[G->vertex_num];
    struct Edge edge_list[G->edge_num];

    ; i < G->vertex_num; i++){
        vertex_list[i] = i;
    }
    ; i < G->vertex_num; i++){
        for(j = i; j < G->vertex_num; j++){
            if(Infinity != G->map[i][j]){
                edge_list[index].start = i;
                edge_list[index].end = j;
                edge_list[index].weight = G->map[i][j];
                index++;
            }
        }
    }
    qsort(edge_list, G->edge_num, sizeof(struct Edge), comp);
    ; i < G->edge_num; i++){
        if(vertex_list[edge_list[i].start] != vertex_list[edge_list[i].end]){
            ; j < G->vertex_num; j++){
                if(vertex_list[j] == vertex_list[edge_list[i].end]){
                    vertex_list[j] = vertex_list[edge_list[i].start];
                }
            }

            sum += edge_list[i].weight;
            printf("%d %d\n", edge_list[i].start, edge_list[i].end);
        }
    }

    return sum;
}

void Init(struct Graph *G){
    int i, j, start, end, weight;

    scanf("%d%d", &(G->edge_num), &(G->vertex_num));
    ; i < G->vertex_num; i++){
        ; j < G->vertex_num; j++){
            G->map[i][j] = Infinity;
        }
    }
    ; i < G->edge_num; i++){
        scanf("%d%d%d", &start, &end, &weight);
        G->map[start][end] = G->map[end][start] = weight;
    }
}

void Output(struct Vertex vertex_list[ ], int size){
    int i;

    ; i < size; i++){
        printf("%d %d\n", i, vertex_list[i].adjacent_vertex);
    }
}

int main(){
    struct Graph G;
    struct Vertex *vertex_list;
    int sum;

    Init(&G);
    vertex_list = (struct Vertex*)malloc(sizeof(struct Vertex) * G.vertex_num);
    sum = Prim(&G, vertex_list, );
    printf("%d\n", sum);
    Output(vertex_list, G.vertex_num);
    sum = Kruskal(&G);
    printf("%d\n", sum);
}

Prim算法和Kruskal算法(图论中的最小生成树算法)的更多相关文章

  1. 转载:最小生成树-Prim算法和Kruskal算法

    本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...

  2. 最小生成树之Prim算法和Kruskal算法

    最小生成树算法 一个连通图可能有多棵生成树,而最小生成树是一副连通加权无向图中一颗权值最小的生成树,它可以根据Prim算法和Kruskal算法得出,这两个算法分别从点和边的角度来解决. Prim算法 ...

  3. java实现最小生成树的prim算法和kruskal算法

    在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...

  4. 最小生成树——Prim算法和Kruskal算法

    洛谷P3366 最小生成树板子题 这篇博客介绍两个算法:Prim算法和Kruskal算法,两个算法各有优劣 一般来说当图比较稀疏的时候,Kruskal算法比较快 而当图很密集,Prim算法就大显身手了 ...

  5. 最小生成树Prim算法和Kruskal算法

    Prim算法(使用visited数组实现) Prim算法求最小生成树的时候和边数无关,和顶点树有关,所以适合求解稠密网的最小生成树. Prim算法的步骤包括: 1. 将一个图分为两部分,一部分归为点集 ...

  6. Prim算法和Kruskal算法

       Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...

  7. 【数据结构】最小生成树之prim算法和kruskal算法

    在日常生活中解决问题经常需要考虑最优的问题,而最小生成树就是其中的一种.看了很多博客,先总结如下,只需要您20分钟的时间,就能完全理解. 比如:有四个村庄要修四条路,让村子能两两联系起来,这时就有最优 ...

  8. Prim算法和Kruskal算法的正确性证明

    今天学习了Prim算法和Kruskal算法,因为书中只给出了算法的实现,而没有给出关于算法正确性的证明,所以尝试着给出了自己的证明.刚才看了一下<算法>一书中的相关章节,使用了切分定理来证 ...

  9. 最小生成树---Prim算法和Kruskal算法

    Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...

  10. prim 算法和 kruskal算法

    Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...

随机推荐

  1. Extjs各版本的下载链接

    Extjs的版本繁多,本文收集了Extjs各个版本的下载链接,包括官网和非官网的,以及各种汉化版api,欢迎大家下载分享. Extjs最新版下载链接:http://www.sencha.com/pro ...

  2. 如何做好APP测试?

    测试一个App具体包括哪些方面,以及每个方面有什么关键点呢? 测试人员常被看作bug寻找者,但你曾想过他们实际是如何开展测试的吗? 你是否好奇他们究竟都做些什么,以及他们如何在一个典型的技术项目中体现 ...

  3. Spring webapp - shutting down threads on Application stop

    显示使用线程池Executors,必须执行 pool.shutdown() 否则会存在线程池泄露: http://stackoverflow.com/questions/22650569/spring ...

  4. Android分享中,如何过滤指定的应用,并且对不同的分享方式发送不同的内容?

    网上找到的一篇关于: 针对不同的应用,使用不同的方式的文章.原文地址 String contentDetails = ""; String contentBrief = " ...

  5. [转]Windows多进程编程

    转自:http://blog.csdn.net/bxhj3014/article/details/2082255 一.进程的概念       进程是是一个正在运行的程序的实例(飘---),是系统分配资 ...

  6. ant 构建时遇到 “非法字符: \65279”的解决办法

    今天使用CI做版本构建时候碰到了这样一个问题,有个activity对应的java源码始终编译报错,错误发生在文件第一行. 出错内容是: *.java:1: 非法字符: \65279    [javac ...

  7. Android OpenCV 图像识别

    最近打算写一个android 平台opencv 的小程序,着手查找了一下资料.网络上的资料参差不齐,有一些都比较老旧,我参考了前面的方法找到了一个简单的搭建方法,分享给大家. 0,环境的搭建: jav ...

  8. canvas draw a image

    var c = context.getContext("2d"); var cimg = new Image(); cimg.src = "img path"; ...

  9. 转:Android Webview 加载外部html时选择加载本地的js,css等资源文件

    原文地址:http://m.blog.csdn.net/blog/qduningning/43196819 在使用WebView加载网页的时候,有一些固定的资源文件如js的jquery包,css,图片 ...

  10. Flash插件地址

    Flash插件地址: http://get.adobe.com/cn/flashplayer/存档版本地址: http://helpx.adobe.com/flash-player/kb/archiv ...