贪心算法 最小生成树prim与单源最短路径dijkstra
来源:互联网 发布:推荐美图软件 编辑:程序博客网 时间:2024/06/05 16:35
转自:http://blog.csdn.net/kejie1235/article/details/8145676
相信很多数据结构书上都讲了两种有关“最小生成树”的算法求解,两种都是基于贪心算法。其中prim算法是适合于稠密图,他的基本思想是从一个节点开始,沿着它的边寻找最短路径的边,并将其并入到开始节点中去,然后再次从开始节点以及刚刚并入的节点的边中寻找”最短路径“并入其中,然后依次循环。。。。
其中的原理很简单,很多数据结构的书上都讲过,但是其中的代码对于初学者还是比较困难的(比如我),我再网上找了很多资料然后发现其中一种思想比较简单,再这里跟大家分享。
首先,要用二维数组记录点和权值。如上图所示无向图:
int map[7][7];
map[1][2]=map[2][1]=4;
map[1][3]=map[3][1]=2;
......
然后再求最小生成树。具体方法是:
1.先选取一个点作起始点,然后选择它邻近的权值最小的点(如果有多个与其相连的相同最小权值的点,随便选取一个)。如1作为起点。
visited[1]=1;
pos=1;
//用low[]数组不断刷新最小权值,low[i](0<i<=点数)的值为:i点到邻近点(未被标记)的最小距离。
low[1]=0; //起始点i到邻近点的最小距离为0
low[2]=map[pos][2]=4;
low[3]=map[pos][3]=2;
low[4]==map[pos][4]=3;
low[5]=map[pos][5]=MaxInt; //无法直达
low[6]=map[pos][6]=MaxInt;
2.再在伸延的点找与它邻近的两者权值最小的点。
//low[]以3作当前位置进行更新
visited[3]=1;
pos=3;
low[1]=0; //已标记,不更新
low[2]=map[1][2]=4; //比5小,不更新
low[3]=2; //已标记,不更新
low[4]=map[1][4]=3; //比1大,更新后为:low[4]=map[3][4]=1;
low[5]=map[1][5]=MaxInt;//无法直达,不更新
low[6]=map[1][6]=MaxInt;//比2大,更新后为:low[6]=map[3][6]=2;
3.如此类推...
[cpp] view plain copy #include <iostream> #include <string.h> using namespace std; const int MAX=0x3f3f3f3f; const int N =100; int map[N][N]; //二维数组表示图 从 (1顶点)开始 int visited[N]; //表示各个定点是否已加入到了 1 中 int low[N] ; //表示从 1 从到各个定点的最小路径 int prim(int n) { memset(visited,0,sizeof(visited) ); memset(low,MAX,sizeof(low) ); int i,j,result = 0; //表示result各个最小权值之和 int pos = 1; //表示当前加入 1 的顶点 visited[1] = 1; int min; //表示新加入的顶点与 1的比较 for( i=1; i<=n; i++) if( i != pos ) low[i] = map[pos][i] ; //进行 n-1次循环,讲其中的 n-1个顶点并入 1中 for(i=1; i<n; i++ ) { min = MAX; for(j=1;j<=n;j++) if( visited[j]==0 && low[j]< min ) { min = low[j]; pos = j; } result+=min; //计算最短路径总和 visited[pos] = 1; //将最短的顶点加入到 1 中 //对于新加进来的顶点,将 map[pos][i]与low[i]进行比较,然后更新 low,low【】是专门对 1 号顶点设置的数组 //更新low数组 for(j=1; j<=n;j++) { if( visited[j]==0 && low[j] > map[pos][j]) low[j] = map[pos][j]; } //下面是dijkstra与prim算法的区别 贪心时两者的贪心方式不同 /*for(j=1; j<=n; j++) { if(visited[j]== 0; map[pos][j]+low[pos] < low[j] ) low[j] = map[pos][j]+low[pos]; } */ } return result; } int main() { int n; //顶点个数 while( scanf("%d", &n)!=EOF ) { int v; memset(map,MAX,sizeof(map) ); for(int i=1; i<=n ; i++) for(int j=1; j<=n; j++) { cin>>v; if( v ) //对于map[i][i]以及不可到达 我们输入0 map[i][j] = v; } /*for(int i =1; i<=n; i++) //用来测试输入是否正确, { for(int j=1; j<=n; j++) cout<<map[i][j]<<" "; cout<<endl; }*/ cout<<"The smallest load :"<<prim(n)<<endl; } return 1; }
对于prim程序的实现的思想我们来总结下: 1:其中low数组是对于 1的专用数组,其中low[i]是表示 1 到 i 的最短路径,我们首先从 1出发,找到最短路径 3 ,然后我们将3 并入1 中,也就是将visited[3] = 1; result+=min(其中min是 1到3的路径),然后我们再更新low[],以为3并入1后,我们需要找到1和3两者到其他路径的最短长度,然后将其中的较短者 赋给low。
2:我们再从low中寻找最小路径 并入1 中,然后再更新新节点到1中。一次循环n-1次。。。。
我们始终比较的是low数组,其中的最小值,得出最小值后,然后将新节点与low比较,更新low,始终保持low是当前路径的最小值,然后再次对low进行比较,个人以为这种编程思想适合新手理解,所以在这里和大家分享。
二者的不同之处在于“权值最低”的定义不同,Prim的“权值最低”是相对于U中的任意一点而言的,也就是把U中的点看成一个整体,每次寻找V-U中跟U的距离最小(也就是跟U中任意一点的距离最小)的一点加入U;而Dijkstra的“权值最低”是相对于v0而言的,也就是每次寻找V-U中跟v0的距离最小的一点加入U。
一个可以说明二者不等价的例子是有四个顶点(v0, v1, v2, v3)和四条边且边值定义为(v0, v1)=20, (v0, v2)=10, (v1, v3)=2, (v3, v2)=15的图,用Prim算法得到的最小生成树中v0跟v1是不直接相连的,也就是在最小生成树中v0v1的距离是v0->v2->v3->v1的距离是27,而用Dijkstra算法得到的v0v1的距离是20,也就是二者直接连线的长度。
- 贪心算法 最小生成树prim与单源最短路径dijkstra
- 贪心算法之最小生成树prim与单源最短路径dijkstra
- 最小生成树Prim算法和单源最短路径Dijkstra算法
- 关于图的常用算法——Dijkstra单源最短路径、Floyd多源最短路径、Prim和Kruskal最小生成树算法
- 算法篇-7-贪心算法-Huffman编码&Dijkstra单源最短路径&Kruskal最小生成树
- 最小生成树Prim算法(贪心算法)
- 贪心算法 - 最小生成树 Prim算法
- 贪心算法 - 最小生成树 Prim算法
- 贪心算法之Prim最小生成树
- 最小生成树prim算法(贪心)
- 图的邻接矩阵表示形式,DFS和BFS,最小生成树Prim和Kruscal,单源最短路径Dijkstra算法
- 【算法】prim算法(最小生成树)(与Dijkstra算法的比较)
- 浅析最小生成树和单源最短路径的区别(含Prim、Kruskal、Dijkstra、Bellman-Ford)
- 最小生成树(MST)Prim算法 贪心算法
- 最小生成树的prim算法贪心正确性的证明
- POJ1258--贪心&最小生成树的prim算法
- 最小生成树的prim算法贪心正确性的证明
- Prim---求最小生成树(贪心算法)
- 聊天界面以及contextm
- 设计模式(二)重温观察者模式:随便窥探一波BaseAdapter源码
- csplit 分割文件
- Serv-U 6.4 设置教程
- 蓝牙 AVDTP 剖析(二) --- command格式 和 流程
- 贪心算法 最小生成树prim与单源最短路径dijkstra
- Android性能优化总结
- jms介绍
- Maven学习笔记
- [Spring MVC] - SpringMVC的各种参数绑定方式
- Java NIO原理图文分析及代码实现
- duplicate symbols for architecture x86_64
- vsftpd、sftp配置
- Spring学习(二)