Dijkstra算法几大模板

主要分为五部分

  1. 邻接矩阵版
  2. 主函数
  3. 普通邻接表版
  4. vector版
  5. 优先队列版

算法思想:每次选出dis最小的那个点i,则dis[i]必定为为顶点s到顶点i的最短距离
更新所有与i相邻的顶点的dis值
依据:如果存在一条i到j的最短路径,其经过的节点为(i……k,j)。那么(i……k)的这条路径也必然是i到k的最短路径。

 

 

每个版本的最初都是构建图,首先将图初始化,然后进行加边。对于双向图要注意双向加边。最后进行dijkstra算法,详情请看主函数。

dijkstra算法伪代码:

 

 

 清除所有点的标记

设dis[s] = 0;其它d[i]为无穷大

循环N次

{

    在所有未标记结点中,选出dis值最小的节点x;

    给结点x标记

    对所有从x出发的边(x,y)进行更新

}

本文注意要点:所有版本接口相同,节点编号均从0开始。


 

/***************************
//邻接矩阵版dijkstra算法
***************************/
#define INF 0x3F3F3F3F			//把INF(最大值)设置成0x3f3f3f3f
const int MAXN = 1010;			//所开数组大小可以修改,一般情况1010足够
int G[MAXN][MAXN];				//G[a][b]表示a,b的权值,G[][]二维数组为构建的邻接矩阵
int vis[MAXN];					//vis[a]记录是否已经查看过'a'点vis[a] == 1 表示已经查看过改点
int dis[MAXN];					//dis[a]记录从起点到'a'点之间的最短路径
//初始化函数,应该在加第一条边之前进行初始化
void init(int n){//n表示gongyoun个点
    for(int i=0;i 
 
  

这样邻接矩阵版的dij就结束了。不仅包含了dij的算法内涵还有邻接矩阵的相关知识。

此处当然应该是上面的几个函数到底怎么用,让我们再贴代码,此处给出杭电oj1874 题解答,下为题目连接:

http://acm.hdu.edu.cn/showproblem.php?pid=1874

 

#include //此处头文件几乎包含常见文件,可各取所需
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

/*此处应加入模板*/
int main()
{	
	int n,m;
	while(cin>>n>>m)
	{
		init(n);//对图进行初始化
		int u,v,d;
		for(int i = 0;i>u>>v>>d;
			add_edge(u,v,d);//
			add_edge(v,u,d);//正反双向加边,题中给出为双向图
		}
		
		int s,t;
		cin>>s>>t;//起点终点
		dijkstra(s,n);//调用函数进行最短路径求解
		int di;
		di = dis[t];//dis[t]即为s到t的最短路径权值
		if(di == INF)
			cout<<"-1"<


这道题的解答是一个纯粹的最短路径的题,很适合熟悉dlj算法。

下面给出其他三种更高效的模板:/*上面已经清晰的不再赘述*/

 

/****************************
//普通邻接表版dijkstra算法
****************************/
//对于邻接表的方法主要的就是如何用邻接表存图,此处不再赘述,可百度各种资料
#define INF 0x3F3F3F3F
const int MAXN_EDGE = 200010;
const int MAXN_NODE = 100010;
int Next[MAXN_EDGE], head[MAXN_NODE],To[MAXN] ,G[MAXN_EDGE], w[MAXN_EDGE];
int tot;
void init(int n){
    tot = 0;
    for(int i = 0; i < n; i++){
        head[i] = -1;
    }
}
void add_edge(int u,int v,int d){
    w[tot] = d;
    To[tot] = v;
    Next[tot] = head[u];
    head[u] = tot++;
}
int vis[MAXN];
int dis[MAXN];
void dijkstra(int s,int n){
    for(int i = 0;i PII;//需要用到pair
const int MAXN = 100010;//满足需求即可
vector G[MAXN];//用到vector//
//初始化
void init(int n){
    for(int i=0;i


下面是vector版的dij复杂度基本上也是O(n*n)

/************************
//vector版dijkstra算法
************************/
//对于vector版本
#define INF 0x3FFFFFFF
typedef pair PII;//需要用到pair
const int MAXN = 100010;//满足需求即可
vector G[MAXN];//用到vector//
//初始化
void init(int n){
    for(int i=0;i

 

下面是优先队列版dij。时间复杂度得到优化为哦O(n*log(n))

/**************************
//优先队列版dijkstra算法
**************************/
//优先队列对dij算法进行了优化降低了算法复杂度
//一般推荐使用此种方法
#define INF 0x3FFFFFFF
#define PB(X) push_back(X)
#define MP(X,Y) make_pair(X,Y)
typedef pairPII;
typedef vectorVII;

const int MAXN = 100010;
vector G[MAXN];
void add_edge(int u,int v,int d){
    G[u].PB(MP(v,d));
}
void init(int n){
    for(int i=0;i >q;//声明优先队列:每次从队列中取出的是具有最高优先权的元素。
    //优先队列第一个参数为比较类型,第二个为容器类型,第三个为比较函数。
	//greater实现小顶堆//less 实现大顶堆(默认为大顶堆)
	q.push(MP(dis[s],s));//将他本身先推进优先队列
    while(!q.empty()){//当队列空时已将所有边加入队列并推出
        PII p = q.top();
        int x = p.second;
        q.pop();
        if(vis[x])continue;
        vis[x] = 1;
        for(int i=0;i

到这里4中不同的算法实现就讲完了,主要的就是看懂代码,最好自己是实现一遍。其中邻接矩阵和邻接表最容易体现dijkstra的精髓。谢谢。

 

 

 

 

 

 

 

 

 

 

 

 

 


 

你可能感兴趣的:(数据结构,dijkstra)