Dijkstra和Prim算法的区别
Dijkstra和Prim算法的区别
1.先说说prim算法的思想:
众所周知,prim算法是一个最小生成树算法,它运用的是贪心原理(在这里不再证明),设置两个点集合,一个集合为要求的生成树的点集合A,另一个集合为未加入生成树的点B,它的具体实现过程是:
第1步:所有的点都在集合B中,A集合为空。
第2步:任意以一个点为开始,把这个初始点加入集合A中,从集合B中减去这个点(代码实现很简单,也就是设置一个标示数组,为false表示这个点在B中,为true表示这个点在A中),寻找与它相邻的点中路径最短的点,如后把这个点也加入集合A中,从集合B中减去这个点(代码实现同上)。
第3步:集合A中已经有了多个点,这时两个集合A和B,只要找到A集合中的点到B集合中的点的最短边,可以是A集合中的与B集合中的点的任意组合,把这条最短边有两个顶点,把在集合B中的顶点加入到集合A中,(代码实现的时候有点技巧,不需要枚举所有情况,也就是更新操作)。
第4步:重复上述过程。一直到所有的点都在A集合中结束。
2.说说dijkstra算法的过程:
这个算法的过程有比prim算法的过程稍微多一点点步骤,但是思想确实巧妙的,也是贪心原理,它的目的是求某个源点到目的点的最短距离,总的来说,dijkstra算法也就是求某个源点到目的点的最短路,求解的过程也就是求源点到整个图的最短距离,次短距离,第三短距离等等(这些距离都是源点到某个点的最短距离)。。。。。求出来的每个距离都对应着一个点,也就是到这个点的最短距离,求的也就是原点到所有点的最短距离,并且存在了一个二维数组中,最后给出目的点就能直接通过查表获得最短距离。
第1步:以源点(假设是s1)为开始点,求最短距离,如何求呢? 与这个源点相邻的点与源点的距离全部放在一个数组dist[]中,如果不可达,dist[]中为最大值,这里说一下,为什么要是一维数组,原因是默认的是从源点到这个一维数组下标的值,只需要目的点作为下标就可以,这时从源点到其他点的最短的“一”条路径有了,只要选出dist[]中最小的就行(得到最短路径的另一个端点假设是s2)。
第2步:这时要寻找源点(假设是s1)到另外点的次短距离,这个距离或者是dist[]里面的值,或者是从第1步中选择的那个最短距离 + 从找到点(假设是s2)出发到其他点的距离(其实这里也是一个更新操作,更新的是dist[]里面的值),如果最短距离 + 从这点(假设是s2)到其他点的距离,小于dist[]里面的值,就可以更新dist[]数组了,然后再从dist[]数组中选一个值最小的,也就是第“二”短路径(次短路径)。
第3步:寻找第“三”短路径,这时同上,第二短路径的端点(s3)更新与之相邻其他的点的dist[]数组里面的值。
第4步:重复上述过程n - 1次(n指的是节点个数),得出结果,其实把源点到所有点的最短路径求出来了,都填在了dist[]表中,要找源点到哪个点的最短路,就只需要查表了。
Dijkstra模版:
//dijkstra算法模版,狄杰斯特拉算法模板,单源最短路模板
//dijkstra算法模版 #include <stdio.h>
#include <string.h>
#define MaxN 1001
#define MaxInt 200000000
int map[MaxN][MaxN],dist[MaxN];
bool mark[MaxN];
int n,start,end;
int main()
{
int i,j,min1,minj,temp; //****************输入**********************
scanf("%d%d%d",&n,&start,&end);
for (i=;i<=n;i++)
for (j=;j<=n;j++)
scanf("%d",&map[i][j]);
//******************************************
//*****************初始化**********************
for (i=;i<=MaxN;i++)
dist[i]=MaxInt;
memset(mark,,sizeof(mark));
dist[start]=; //把起点并入集合,搜索时就可以从起点寻找到第一条最短的边了
//*********************************************
for (i=;i<=n-;i++)
{
min1=MaxInt;
for (j=;j<=n;j++) //查找到原集合的最短的边
{
if (!mark[j]&&dist[j]<min1)
{
min1=dist[j];
minj=j;
}
}
mark[minj]=;
for (j=;j<=n;j++) //每并入一个点都要对原来的边进行修正,保证任意时刻源点到目标点的距离都是最短的。
{
if (!mark[j]&&map[minj][j]>)
{
temp=dist[minj]+map[minj][j];
if (temp<dist[j])
dist[j]=temp;
}
}
}
//***********输出***************
printf("%d\n",dist[end]);
//******************************
return ;
}
Prim算法中寻找的是下一个与MST中任意顶点相距最近的顶点;
Dijkstra算法寻找的是下一个离给定顶点(单源)最近的顶点。
另外,当有两条具有同样的最小权值的边可供选择时,任选一条即可,所以构造的MST不是惟一的。
Prim算法和Dijkstra算法十分相似,惟一的区别是: Prim算法要寻找的是离已加入顶点距离最近的顶点;
Dijkstra算法是寻找离固定顶点距离最近的顶点。
所以Prim算法的时间复杂度分析与Dijkstra算法相同,都是 O(|V^2|) 【拓】:Kruskal算法:http://baike.baidu.com/link?url=MchMLaw4a3nLu3bWSoEUEak-DYbM8n0H27ANKE5-Gv_frudxAvGfsqdpNRqDtdB0
克鲁斯卡尔(Kruskal)算法(只与边相关)
算法描述:克鲁斯卡尔算法需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边又关系,可以证明其时间复杂度为O(eloge)。
算法过程:
1.将图各边按照权值进行排序
2.将图遍历一次,找出权值最小的边,(条件:此次找出的边不能和已加入最小生成树集合的边构成环),若符合条件,则加入最小生成树的集合中。
不符合条件则继续遍历图,寻找下一个最小权值的边。
3.递归重复步骤1,直到找出n-1条边为止(设图有n个结点,则最小生成树的边数应为n-1条),算法结束。得到的就是此图的最小生成树。
克鲁斯卡尔(Kruskal)算法因为只与边相关,则适合求稀疏图的最小生成树。而prime算法因为只与顶点有关,所以适合求稠密图的最小生成树。
代码:
#include<iostream>
#include<cstring>
#include<string> #include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 1000
int father[MAX], son[MAX];
int v, l; typedef struct Kruskal //存储边的信息
{
int a;
int b;
int value;
}; bool cmp(const Kruskal & a, const Kruskal & b)
{
return a.value < b.value;
} int unionsearch(int x) //查找根结点+路径压缩
{
return x == father[x] ? x : unionsearch(father[x]);
} bool join(int x, int y) //合并
{
int root1, root2;
root1 = unionsearch(x);
root2 = unionsearch(y);
if(root1 == root2) //为环
return false;
else if(son[root1] >= son[root2])
{
father[root2] = root1;
son[root1] += son[root2];
}
else
{
father[root1] = root2;
son[root2] += son[root1];
}
return true;
} int main()
{
int ncase, ltotal, sum, flag;
Kruskal edge[MAX];
scanf("%d", &ncase);
while(ncase--)
{
scanf("%d%d", &v, &l);
ltotal = , sum = , flag = ;
for(int i = ; i <= v; ++i) //初始化
{
father[i] = i;
son[i] = ;
}
for(int i = ; i <= l ; ++i)
{
scanf("%d%d%d", &edge[i].a, &edge[i].b, &edge[i].value);
}
sort(edge + , edge + + l, cmp); //按权值由小到大排序
for(int i = ; i <= l; ++i)
{
if(join(edge[i].a, edge[i].b))
{
ltotal++; //边数加1
sum += edge[i].value; //记录权值之和
cout<<edge[i].a<<"->"<<edge[i].b<<endl;
}
if(ltotal == v - ) //最小生成树条件:边数=顶点数-1
{
flag = ;
break;
}
}
if(flag) printf("%d\n", sum);
else printf("data error.\n");
}
return ;
}
Dijkstra和Prim算法的区别的更多相关文章
- Prim算法与Dijkstra算法的联系与区别
/* 图结构,邻接矩阵形式 */ ElemType nodes[n]; int edges[n][n]; prim_or_dijkstra( int index, bool usePrim ) /* ...
- 【最短路算法】Dijkstra+heap和SPFA的区别
单源最短路问题(SSSP)常用的算法有Dijkstra,Bellman-Ford,这两个算法进行优化,就有了Dijkstra+heap.SPFA(Shortest Path Faster Algori ...
- Dijkstra 算法、Kruskal 算法、Prim算法、floyd算法
1.dijkstra算法 算最短路径的,算法解决的是有向图中单个源点到其他顶点的最短路径问题. 初始化n*n的数组. 2.kruskal算法 算最小生成树的,按权值加入 3.Prim算法 类似dijk ...
- 数据结构与算法系列研究七——图、prim算法、dijkstra算法
图.prim算法.dijkstra算法 1. 图的定义 图(Graph)可以简单表示为G=<V, E>,其中V称为顶点(vertex)集合,E称为边(edge)集合.图论中的图(graph ...
- 【算法】prim算法(最小生成树)(与Dijkstra算法的比较)
最小生成树: 生成树的定义:给定一个无向图,如果它的某个子图中任意两个顶点都互相连通并且是一棵树,那么这棵树就叫做生成树.(Spanning Tree) 最小生成树的定义:在生成树的基础上,如果边上有 ...
- Prim算法、Kruskal算法、Dijkstra算法
无向加权图 1.生成树(minimum spanning trees) 图的生成树是它一棵含有所有顶点的无环联通子图 最小生成树:生成树中权值和最小的(所有边的权值之和) Prim算法.Kruskal ...
- 朴素版和堆优化版dijkstra和朴素版prim算法比较
1.dijkstra 时间复杂度:O(n^2) n次迭代,每次找到距离集合S最短的点 每次迭代要用找到的点t来更新其他点到S的最短距离. #include<iostream> #inclu ...
- 算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
一.名称 动态规划法应用 二.目的 1.贪婪技术的基本思想: 2.学会运用贪婪技术解决实际设计应用中碰到的问题. 三.要求 1.实现基于贪婪技术思想的Prim算法: 2.实现基于贪婪技术思想的Dijk ...
- 【树论 1】 prim算法的学习和使用
进阶版神犇可以看看本题解的姊妹篇 Kruskal算法的学习和使用 下面的内容是prim算法 但是最小生成树是什么呢? 标准定义如下:在边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值 ...
随机推荐
- 【PHP】当mysql遇上PHP
博客提纲 利用PHP连接mySQL数据库 两套接口:面向对象和面向过程 实现写改删查(CUBD)实例 通过prepare语句处理相同类型的不同SQL语句 通过bind_param()绑定参数,及相关注 ...
- cad2019卸载/安装失败/如何彻底卸载清除干净cad2019注册表和文件的方法
cad2019提示安装未完成,某些产品无法安装该怎样解决呢?一些朋友在win7或者win10系统下安装cad2019失败提示cad2019安装未完成,某些产品无法安装,也有时候想重新安装cad2019 ...
- python(29)----时间模块
time模块 1. 三种时间表现形式 时间戳(timestamp) 格式化的时间字符串 元祖/结构化时间(struct_time) 2. 时间戳(timestamp) 通常来说,时间戳表示的是从197 ...
- Mybatis 逆向工程学习随笔
一.逆向工程的作用 简单来说,就是替我们生成Java代码. 之前使用Mybatis的Mapper代理方法开发,还需要自己创建实体类,而且属性还得和数据库中的字段对应.这着实是机械化的而且比较麻烦的事, ...
- IntelliJ IDEA中Debug的使用技巧
当运行结果跟我们设想的不一致时,我们就可以用debug进行代码调试,下面是我在日常开发中对debug的一些小结 (一)基本介绍 本篇文章是基于IntelliJ IDEA2018.3.2版本,Debug ...
- [每天解决一问题系列 - 0002] Xcopy cannot copy file with long directory
现象: 当xcopy的文件的全名(包括目录和文件名)的长度超过255字符时,会copy失败,得到insufficient memory错误 解决方法: 在Server 版的OS中,有robcopy命令 ...
- node.js的
node.js入门 http://www.cnblogs.com/rubylouvre/archive/2010/07/15/1778403.html 专题:Node.js专区http://devel ...
- Notepad++中代码格式化插件NppAStyle
本文以图片和说明,手把手教大家怎么让Notepad++中的代码风格看起来更美观. 工具/原料 Windows7 Notepad++ NppAStyle(Notepad++的一个插件) 方法/步骤 直 ...
- Mac系统配置JDK1.8环境变量
1.首先我们得知道JDK目录安装在哪里,按照下面的路径我们可以找到JDK的主目录,如下图所示.这里有两个目录是因为本机较早前安装过早期版本的JDK1.8. /Library/Java/JavaVirt ...
- JavaScript -- Screen
-----041-Screen.html----- <!DOCTYPE html> <html> <head> <meta http-equiv=" ...