Prim算法和Kruskal算法(图论中的最小生成树算法)
最小生成树在一个图中可以有多个,但是如果一个图中边的权值互不相同的话,那么最小生成树只可能存在一个,用反证法很容易就证明出来了。
当然最小生成树也是一个图中包含所有节点的权值和最低的子图。
在一个图中权值最小的那个边一定在最小生成树中,如果一个图包含环,环中权值最大的边一定不在最小生成树中,还有就是连接图的任意两个划分的边中权值最短的那一条一定在最小生成树中。
下面介绍两个算法。
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算法(图论中的最小生成树算法)的更多相关文章
- 转载:最小生成树-Prim算法和Kruskal算法
本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...
- 最小生成树之Prim算法和Kruskal算法
最小生成树算法 一个连通图可能有多棵生成树,而最小生成树是一副连通加权无向图中一颗权值最小的生成树,它可以根据Prim算法和Kruskal算法得出,这两个算法分别从点和边的角度来解决. Prim算法 ...
- java实现最小生成树的prim算法和kruskal算法
在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...
- 最小生成树——Prim算法和Kruskal算法
洛谷P3366 最小生成树板子题 这篇博客介绍两个算法:Prim算法和Kruskal算法,两个算法各有优劣 一般来说当图比较稀疏的时候,Kruskal算法比较快 而当图很密集,Prim算法就大显身手了 ...
- 最小生成树Prim算法和Kruskal算法
Prim算法(使用visited数组实现) Prim算法求最小生成树的时候和边数无关,和顶点树有关,所以适合求解稠密网的最小生成树. Prim算法的步骤包括: 1. 将一个图分为两部分,一部分归为点集 ...
- Prim算法和Kruskal算法
Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...
- 【数据结构】最小生成树之prim算法和kruskal算法
在日常生活中解决问题经常需要考虑最优的问题,而最小生成树就是其中的一种.看了很多博客,先总结如下,只需要您20分钟的时间,就能完全理解. 比如:有四个村庄要修四条路,让村子能两两联系起来,这时就有最优 ...
- Prim算法和Kruskal算法的正确性证明
今天学习了Prim算法和Kruskal算法,因为书中只给出了算法的实现,而没有给出关于算法正确性的证明,所以尝试着给出了自己的证明.刚才看了一下<算法>一书中的相关章节,使用了切分定理来证 ...
- 最小生成树---Prim算法和Kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...
- prim 算法和 kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...
随机推荐
- AFX_MANAGE_STATE(AfxGetStaticModuleState())DLL导出函数包含MFC资源
AFX_MANAGE_STATE(AfxGetStaticModuleState()) 先看一个例子: .创建一个动态链接到MFC DLL的规则DLL,其内部包含一个对话框资源.指定该对话框ID如下: ...
- 安全快速修改Mysql数据库名的5种方法
1. RENAME DATABASE db_name TO new_db_name这个..这个语法在mysql 5.1.7中被添加进来,到了5.1.23又去掉了.据说有可能丢失数据.还是不要用的好.详 ...
- Linux下编译安装PCRE库
备注:如果没有root权限,使用 --prefix 指定安装路径 ./configure --prefix=/home/work/tools/pcre-8.xx =================== ...
- win7下IIS错误:"无法访问请求的页面,因为该页的相关配置数据无效"的解决方法(转)
今天新装win7,然后在IIS下布署了一个网站,布署完成后运行,提示如下错误:HTTP 错误 500.19 - Internal Server Error无法访问请求的页面,因为该页的相关配置数据无效 ...
- OpenStack nova VM migration (live and cold) call flow
OpenStack nova compute supports two flavors of Virtual Machine (VM) migration: Cold migration -- mig ...
- centos7编译安装pure-ftpd-1.0.42
一.下载 wget https://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.42.tar.gz 二.安装 tar xvf ...
- day6-3面向对象高阶
面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中) 对象,根据模板创建的实例(即:对象),实 ...
- Oracle中获取当前时间半小时前的时间
最近项目中有个要根据半个小时前的数据情况判断某一栏位的值,但是一直没想到怎样获取当前时间的半小时前的时间,今天突然想到可以通过sysdate做差来获取,比如sysdate-1这样的,刚开始没有对结果进 ...
- spring定时器设置(转自:http://my.oschina.net/LvSantorini/blog/520049)
转自:http://my.oschina.net/LvSantorini/blog/520049<!-- MessageRequestTask类中包含了msgRequest方法,用于执行定时任务 ...
- Apache配置简单http认证
首先要说明的是这种认证是不安全的,密码是明文传输,因此很容易被各种嗅探软件嗅探到密码,只能用于简单的认证.今天上午把ownCloud卸载了,这玩 意儿中看不中用啊,原来10M的访问速度被限制成了几百K ...