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. Java面试题全集(上)

    2013年年底的时候,我看到了网上流传的一个叫做<Java面试题大全>的东西,认真的阅读了以后发现里面的很多题目是重复且没有价值的题目,还有不少的参考答案也是错误的,于是我花了半个月时间对 ...

  2. Python开发【模块】:Concurrent

    concurrent 模块 回顾: 对于python来说,作为解释型语言,Python的解释器必须做到既安全又高效.我们都知道多线程编程会遇到的问题,解释器要留意的是避免在不同的线程操作内部共享的数据 ...

  3. day17(JDBC入门&jdbcUtils工具介绍)

    day17 JDBC整体思维导图 JDBC入门 导jar包:驱动! 加载驱动类:Class.forName("类名"); 给出url.username.password,其中url ...

  4. 【PHP】善用php-fpm的慢执行日志slow log,分析php性能问题

    (转)善用php-fpm的慢执行日志slow log,分析php性能问题  众所周知,mysql有slow query log,根据慢查询日志,我们可以知道那些sql语句有性能问题.作为mysql的好 ...

  5. Spark提交应用程序之Spark-Submit分析

    1.提交应用程序 在提交应用程序的时候,用到 spark-submit 脚本.我们来看下这个脚本: if [ -z "${SPARK_HOME}" ]; then export S ...

  6. POJ1523:SPF(无向连通图求割点)

    题目:http://poj.org/problem?id=1523 题目解析: 注意题目输入输入,防止PE,题目就是求割点,并问割点将这个连通图分成了几个子图,算是模版题吧. #include < ...

  7. jq的$(function(){})与window.onload的区别

    最近一直在研究jq的源码,书写jq的代码我们通常会包裹在一个$(function(){})函数中,jq的$(function(){})也就是$(document).ready(function(){} ...

  8. Check out our list of adidas NMD Singapore retailers

    The adidas NMD Singapore is confirmed to produce on The month of january 14th at select adidas Origi ...

  9. WCF标准绑定以及传输协议与编码格式

    WCF 定义了9 种标准绑定: 基本绑定(Basic Binding) 由BasicHttpBinding类提供.基本绑定能够将WCF服务公开为旧的ASMX Web服务,使得旧的客户端能够与新的服务协 ...

  10. (21)纹理缓存(Texture Cache)

    简介 纹理缓存是将纹理缓存起来方便之后的绘制工作.每一个缓存的图像的大小,颜色和区域范围都是可以被修改的.这些信息都是存储在内存中的,不用在每一次绘制的时候都发送给GPU. CCTextureCach ...