Dijkstra算法分析

题目分析参照《数据结构》(严蔚敏)7-6节

最短路径问题描述

参照日常生活中的公交查询系统。我们有选项:

少换乘/最少站数

价格最少/时间最短....

(ps:下边这个图是网页查询的,略有出入)

根据这样的分类。我们可以将最短路径分为:结点最少(经过的站数最少),权值最小(这个就是个心里期望了,看你是相花费时间最少,金钱最少....)

结点最少

(参照途中描述)

由此可以看出,对于经过站点最少,换乘最少这种问题,我们只需要对图进行广度遍历,即可获取相关结果。

我们重点分析下面的情况

权值最小(花费最少)

理论:从A到B,他们之间的路径要么是A->B,要么经过中间节点  A->..->B其最短路径也就是两条路径中最短的一条。

于是有:对于最短路径问题,我们只需要利用动态规划,在遍历中更新,逐步获取最短路径。

具体分析图如下

如上为寻找下标0-2结点过程的分析。对应代码

    bool Dijkstra(const V&src,const V&dst,int &ret)
{
//如果只有顶点,那么返回true,ret =0;
if (_size <= )
{
ret = ;
return true;
}
int cur = FindIndexV(src);
int end = FindIndexV(dst); int beg = cur; size_t wights[] = {};
int paths[] = {};
for (size_t i = ; i < _size; ++i)
{
wights[i] = -;
paths[i] = src;
}
wights[cur] = ;
paths[cur] = ; Edge* pcur = _eList[cur];
//首次更新
while (pcur)
{
wights[pcur->_dst] = pcur->_wight;
pcur = pcur->_next;
}
pcur = _eList[cur]; int visitedCount = ;
while (cur!=end)//未走到目的
{
if (cur == beg)
visitedCount++;
//如果起点没有路径且目标不可达//或者回到起点了
if (pcur == NULL&&wights[dst] == -||cur == beg&&visitedCount==)
{
return false;
} //获取最短边
Edge* minCur = _eList[cur];
Edge* pcur = _eList[cur];
while (pcur)
{
if (minCur->_wight > pcur->_wight)
minCur = pcur;
pcur = pcur->_next;
}
cur = minCur->_src;
//根据局部最短更新路径
if (wights[cur] + minCur->_wight < wights[minCur->_dst])
{
wights[minCur->_dst] = wights[cur] + minCur->_wight;
paths[minCur->_dst] = minCur->_src;
} cur = minCur->_dst;
if (minCur->_dst == FindIndexV(dst))
{
ret = wights[minCur->_dst];
return true;
}
}
}

以下是整个图项目文件以及对应于最短路径的测试用例

#pragma once
//邻接表实现图 #include<queue>
#include<stack>
#include"UnionFindset.h" #include<map>
template<class V, class E>
struct Edge
{
Edge(size_t dst,size_t src, const E&e)
:_wight(e)
,_dst(dst)
,_src(src)
, _next(NULL)
{}
E _wight; //权值,边比重
size_t _dst; //目的顶点下标
size_t _src; //源顶点下标
struct Edge<V, E>* _next; bool operator<(const Edge* &ed)
{
return _wight < ed->_wight;
}
}; template<class V,class E>
class GraphList
{
typedef Edge<V, E> Edge;
protected:
V* _vArr; //顶点存储数组
size_t _size; Edge** _eList; //边存储指针数组 public:
GraphList(const V* vArray, const size_t size)
:_size(size)
, _vArr(new V[size])
{
//初始化顶点保存
for (size_t i = ; i < size; ++i)
{
_vArr[i] = vArray[i];
}
//初始化边结构
_eList = new Edge*[size];
memset(_eList, , sizeof(Edge*)*size);
} int FindIndexV(const V& v) const
{
for (size_t i = ; i < _size; ++i)
{
if (_vArr[i] == v)
return i;
}
return -;
} //添加v1->v2的边
void AddEdge2(const V& v1, const V&v2, const E& e, bool IsDir = true)
{
int ind1 = FindIndexV(v1);
int ind2 = FindIndexV(v2); Edge* cur = new Edge(ind2, ind1, e); cur->_next = _eList[ind1];
_eList[ind1] = cur; if (!IsDir)
{
Edge* cur = new Edge(ind1, ind2, e);
cur->_next = _eList[ind2];
_eList[ind2] = cur;
} } void Display()const
{
cout << "顶点集合" << endl;
for (size_t i = ; i < _size; ++i)
{
cout << _vArr[i] << " ";
}
cout << endl << "边表示" << endl; for (size_t i = ; i < _size; ++i)
{
cout << "边["<<i << "]>>";
Edge* cur = _eList[i];
while (cur)
{
//cout << "[" << cur->_dst << "]" << cur->_wight << " ";
//printf("[%d]:", cur->_dst, cur->_wight);
cout << "[" << cur->_dst << "]" << cur->_wight << "--> ";
cur = cur->_next;
}
cout <<"NULL"<< endl;
}
cout << endl;
} //广度优先
void BSP(const V& root)
{
cout << "广度优先遍历:" << endl;
bool *visited = new bool[_size](); queue<int> q;
int index = FindIndexV(root); q.push(index); while (!q.empty())
{
index = q.front();
if (visited[index] == false)
{
cout << _vArr[index]<<"-->";
} visited[index] = true; q.pop();
Edge* cur = _eList[index];
while (cur)
{
if (visited[cur->_dst] == false)//未访问过那么压入
{
q.push(cur->_dst);
}
cur = cur->_next;
}
}
cout << endl << endl;
} //深度优先
void DSP(const V& root)
{
//
cout << "深度优先遍历:" << endl;
_DSP(root);
cout << endl << endl;
}
void _DSP(const V& root)
{
static bool *visited = new bool[_size]();
int index = FindIndexV(root);
if (visited[index] == false)
{
cout << _vArr[index] << "-->";
visited[index] = true;
} Edge* cur = _eList[index]; while (cur)
{
if (visited[cur->_dst] == false)
_DSP(_vArr[cur->_dst]);
cur = cur->_next;
}
if (cur == NULL)
return;
} //在所有边中获取最小权值的边
int FindMinEdgeIndex(vector<Edge*>&v)
{
int min = ;
for (size_t i = ; i < v.size(); ++i)
{
if (v[i]->_wight < v[min]->_wight)
min = i;
}
return min;
} bool Kruskal(GraphList<V,E>& minTree)
{
vector<Edge*> ve;
for (size_t i = ; i < _size; ++i)
{
Edge* cur = _eList[i];
while (cur)
{
//只插入有效边
ve.push_back(cur);
cur = cur->_next;
}
} UnionFindSet us(_size); while (!ve.empty())
{
//找到最小权值边
int i = FindMinEdgeIndex(ve);
//并查集插入相关结点
bool sure = us.Combine(ve[i]->_src, ve[i]->_dst);
if (sure) //如果不是连通的,那么加入该边
{
minTree.AddEdge2(_vArr[ve[i]->_src], _vArr[ve[i]->_dst], ve[i]->_wight);
}
ve.erase(ve.begin()+i);
} return us.IsOnlyOneRoot();
} //在相关边中获取最小权值的边
int FindMinEdgeIndexByInGraph(vector<Edge*>&v,vector<int>& nodes)
{
if (nodes.size() == )
return FindMinEdgeIndex(v);
int min = -;
for (size_t i = ; i < v.size(); ++i) //遍历所有结点
{
//如果 if (v[i]->_wight < v[min]->_wight)
{
bool inNodes = false;
for (size_t j = ; j < nodes.size(); ++i)
{
if (v[i]->_dst == nodes[j] || v[i]->_src == nodes[j])
{
inNodes = true;
break;
}
}
if(inNodes)
min = i;
} }
return min;
}
bool Prim(GraphList<V, E>& minTree)
{
vector<Edge*> ve;
vector<int> inGraph;
for (size_t i = ; i < _size; ++i)
{
Edge* cur = _eList[i];
while (cur)
{
//只插入有效边
ve.push_back(cur);
cur = cur->_next;
}
} UnionFindSet us(_size); while (!ve.empty())
{
//找到最小权值边
int i = FindMinEdgeIndexByInGraph(ve,inGraph);
if (us.IsOnlyOneRoot())
return true; else if (i == - && !us.IsOnlyOneRoot())
return false; //并查集插入相关结点
bool sure = us.Combine(ve[i]->_src, ve[i]->_dst);
if (sure) //如果不是连通的,那么加入该边
{
minTree.AddEdge2(_vArr[ve[i]->_src], _vArr[ve[i]->_dst], ve[i]->_wight);
}
ve.erase(ve.begin() + i);
} return us.IsOnlyOneRoot();
}
//size_t wights[6] = {};
//int paths[6] = {};
bool Dijkstra(const V&src,const V&dst,int &ret)
{
//如果只有顶点,那么返回true,ret =0;
if (_size <= )
{
ret = ;
return true;
}
int cur = FindIndexV(src);
int end = FindIndexV(dst); int beg = cur; size_t wights[] = {};
int paths[] = {};
for (size_t i = ; i < _size; ++i)
{
wights[i] = -;
paths[i] = src;
}
wights[cur] = ;
paths[cur] = ; Edge* pcur = _eList[cur];
//首次更新
while (pcur)
{
wights[pcur->_dst] = pcur->_wight;
pcur = pcur->_next;
}
pcur = _eList[cur]; int visitedCount = ;
while (cur!=end)//未走到目的
{
if (cur == beg)
visitedCount++;
//如果起点没有路径且目标不可达//或者回到起点了
if (pcur == NULL&&wights[dst] == -||cur == beg&&visitedCount==)
{
return false;
} //获取最短边
Edge* minCur = _eList[cur];
Edge* pcur = _eList[cur];
while (pcur)
{
if (minCur->_wight > pcur->_wight)
minCur = pcur;
pcur = pcur->_next;
}
cur = minCur->_src;
//根据局部最短更新路径
if (wights[cur] + minCur->_wight < wights[minCur->_dst])
{
wights[minCur->_dst] = wights[cur] + minCur->_wight;
paths[minCur->_dst] = minCur->_src;
} cur = minCur->_dst;
if (minCur->_dst == FindIndexV(dst))
{
ret = wights[minCur->_dst];
return true;
}
}
} ~GraphList()
{
if (_vArr)
{
delete[]_vArr;
_vArr = NULL;
}
if (_eList)
{
for (size_t i = ; i < _size;++i)
{
while (_eList[i] != NULL)
{
Edge* del = _eList[i];
_eList[i] = del->_next;
delete del;
del = NULL;
}
}
}
}
}; void testD()
{
//int vArr1[] = { 1,2,3,4,5,6,7,8,9 };
//GraphList<int, int> gh1(vArr1, sizeof(vArr1) / sizeof(vArr1[0])); //gh1.AddEdge2(1, 2, 11);
//gh1.AddEdge2(1, 3, 33);
//gh1.AddEdge2(1, 5, 33);
//gh1.AddEdge2(2, 3, 33);
//gh1.AddEdge2(2, 6, 99);
//gh1.AddEdge2(5, 3, 33);
//gh1.AddEdge2(3, 4, 44);
//gh1.AddEdge2(4, 5, 55);
//gh1.AddEdge2(4, 7, 32);
//gh1.AddEdge2(7, 8, 65);
//gh1.AddEdge2(1, 9, 12);
//gh1.AddEdge2(9, 7, 22); int vArr1[] = { ,,,,,};
GraphList<int, int> gh1(vArr1, sizeof(vArr1) / sizeof(vArr1[])); gh1.AddEdge2(, , );
gh1.AddEdge2(, , );
gh1.AddEdge2(, , );
gh1.AddEdge2(, , );
gh1.AddEdge2(, , );
gh1.AddEdge2(, , );
gh1.AddEdge2(, , );
gh1.AddEdge2(, , ); gh1.Display(); gh1.BSP();
gh1.DSP();
GraphList<int, int> gMin(vArr1, sizeof(vArr1) / sizeof(vArr1[]));
GraphList<int, int> gMin1(vArr1, sizeof(vArr1) / sizeof(vArr1[]));
if (gh1.Kruskal(gMin))
{
cout << "kruskal最小生成树:" << endl;
gMin.Display();
}
if (gh1.Prim(gMin1))
{
cout << "prim最小生成树:" << endl;
gMin1.Display();
} int ret = ;
if (gh1.Dijkstra(, , ret))
{
cout <<"gh1.Dijkstra(0, 1, ret)"<< ret << endl;
}
if (gh1.Dijkstra(, , ret))
{
cout << "gh1.Dijkstra(0, 2, ret)" << ret << endl;
}
if (gh1.Dijkstra(, , ret))
{
cout << "gh1.Dijkstra(0, 3, ret)" << ret << endl;
}
if (gh1.Dijkstra(, , ret))
{
cout << "gh1.Dijkstra(0, 4, ret)" << ret << endl;
}
if (gh1.Dijkstra(, , ret))
{
cout << "gh1.Dijkstra(0, 5, ret)" << ret << endl;
}
//char vArr2[] = { 'A','B','C','D','E','F' };
//GraphList<char, int> gh(vArr2, sizeof(vArr2) / sizeof(vArr2[0]));
//gh.AddEdge2('A', 'B', 11);
//gh.AddEdge2('B', 'C', 33);
//gh.AddEdge2('C', 'D', 44);
//gh.AddEdge2('D', 'E', 55);
//gh.AddEdge2('E','F', 66);
//gh.Display(); // gh.BSP('A');
}

参考:http://www.cnblogs.com/hxsyl/archive/2013/08/20/3270401.html

最短路径求解(Dijkstra)的更多相关文章

  1. 最短路径算法——Dijkstra,Bellman-Ford,Floyd-Warshall,Johnson

    根据DSqiu的blog整理出来 :http://dsqiu.iteye.com/blog/1689163 PS:模板是自己写的,如有错误欢迎指出~ 本文内容框架: §1 Dijkstra算法 §2 ...

  2. 最短路径算法-Dijkstra算法的应用之单词转换(词梯问题)(转)

    一,问题描述 在英文单词表中,有一些单词非常相似,它们可以通过只变换一个字符而得到另一个单词.比如:hive-->five:wine-->line:line-->nine:nine- ...

  3. 最短路径问题---Dijkstra算法详解

    侵删https://blog.csdn.net/qq_35644234/article/details/60870719 前言 Nobody can go back and start a new b ...

  4. 最短路径问题----Dijkstra算法的解释

    先上图: 现在要找到地点V1到其余各个地点的最短路径(图中数字的单位默认为km.).有一个原则是:永远找最小,确保无更小. 第一步:v1->v1,v1->v2,...v1->v7的距 ...

  5. 4003.基于Dijsktra算法的最短路径求解

    基于Dijsktra算法的最短路径求解 发布时间: 2018年11月26日 10:14   时间限制: 1000ms   内存限制: 128M 有趣的最短路...火候欠佳,目前还很难快速盲打出来,需继 ...

  6. 基于Dijsktra算法的最短路径求解

    基于Dijsktra算法的最短路径求解   描述 一张地图包括n个城市,假设城市间有m条路径(有向图),每条路径的长度已知.给定地图的一个起点城市和终点城市,利用Dijsktra算法求出起点到终点之间 ...

  7. 最短路径算法Dijkstra和A*

    在设计基于地图的游戏,特别是isometric斜45度视角游戏时,几乎必须要用到最短路径算法.Dijkstra算法是寻找当前最优路径(距离原点最近),如果遇到更短的路径,则修改路径(边松弛). Ast ...

  8. 单源最短路径(dijkstra算法)php实现

    做一个医学项目,当中在病例评分时会用到单源最短路径的算法.单源最短路径的dijkstra算法的思路例如以下: 如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点.那么( ...

  9. 最短路径之Dijkstra算法和Floyd-Warshall算法

    最短路径算法 最短路径算法通常用在寻找图中任意两个结点之间的最短路径或者是求全局最短路径,像是包括Dijkstra.A*.Bellman-Ford.SPFA(Bellman-Ford的改进版本).Fl ...

随机推荐

  1. pta 天梯地图 (Dijkstra)

    本题要求你实现一个天梯赛专属在线地图,队员输入自己学校所在地和赛场地点后,该地图应该推荐两条路线:一条是最快到达路线:一条是最短距离的路线.题目保证对任意的查询请求,地图上都至少存在一条可达路线. 输 ...

  2. 南京网络赛E-AC Challenge【状压dp】

    Dlsj is competing in a contest with n (0 < n \le 20)n(0<n≤20) problems. And he knows the answe ...

  3. 不走标准路的微软:少一个斜杠的URI Path

    今天又被微软不按标准的做法折腾了一下,写篇博文抱怨一下. 我们先来看一下IETF(Internet Engineering Task Force)对URI结构的标准定义(链接): 注意上面的path部 ...

  4. MVC项目,bootstrap升级后index.d.ts编译出错

    安装最新的Typescript组件 下载链接 https://www.microsoft.com/en-us/download/details.aspx?id=48593

  5. java-信息安全(十八)java加密解密,签名等总结

    一.基本概念 加密: 密码常用术语: 明文,密文,加密,加密算法,加密秘钥,解密,解密算法,解密秘钥, 密码分析:分析密文从而推断出明文或秘钥的过程 主动攻击:入侵密码系统,采用伪造,修改,删除等手段 ...

  6. 【转】Deep Learning(深度学习)学习笔记整理系列之(四)

    九.Deep Learning的常用模型或者方法 9.1.AutoEncoder自动编码器 Deep Learning最简单的一种方法是利用人工神经网络的特点,人工神经网络(ANN)本身就是具有层次结 ...

  7. 画柱状图Java

    样例输入:THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG.THIS IS AN EXAMPLE TO TEST FOR YOURHISTOGRAM PROGR ...

  8. Wannafly挑战赛28 Solution

    A:msc和mas Solved. 考虑斐波那契数列,即最多加45次即会超过1e9,直接暴力即可 #include <bits/stdc++.h> using namespace std; ...

  9. uva11795

    这题说的是一个人要消灭 所有的机器人,但是他有他可以消灭的机器人,他可以通过它消灭的机器人的武器去消灭其他的机器人, 给了一个可以消灭的关系的矩阵,计算消灭这些机器人的顺序的不同方案是多少种 , 刚开 ...

  10. Fms3和Flex打造在线视频录制和回放

    本博推荐文章快速导航: Sql Server2005 Transact-SQL 新兵器学习MCAD学习 代码阅读总结 ASP.NET状态管理 DB(数据库)WAPWinFormFlex,Fms aie ...