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. 170628、springboot编程之Druid数据源和监控配置一

    Spring Boot默认的数据源是:org.apache.tomcat.jdbc.pool.DataSource,那么如何修改数据源呢?我已目前使用比较多的阿里数据源Druid为例,如果使用其他的数 ...

  2. input输入框制定输入数据类型匹配

    <input type="text" id="price_169" value="97" style="max-width: ...

  3. Process Monitor分析某个应用行为

    1.打开Process Mointor 2.点击filter-->filter   在弹出的对话框中Architecture 下拉框,选择Process Name 填写要分析的应用程序名字. 点 ...

  4. web应用/http协议/web框架

    一.web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件.应用程序有两种模式C/S.B/S.C/S是客户端 ...

  5. formset批量处理form表单数据

    Formset(表单集)是多个表单的集合.Formset在Web开发中应用很普遍,它可以让用户在同一个页面上提交多张表单,一键添加多个数据 class StudentStudyRecordModel( ...

  6. 优雅的使用Laravel之phpstorm配置

    优雅的使用Laravel之phpstorm配置 先打开一个Laravel 项目,然后在project tool 窗口选择根节点.然后右键->Composer | Init composer . ...

  7. mysql数据库访问权限限制设置

    ---只能本地访问,设置随意访问 update user set host='%' where host='localhost': flush privileges; ---随意访问,设置只能本地访问 ...

  8. Bootstrap table后端分页(ssm版)

    说明bootstrap table可以前端分页,也可以后端sql用limit分页.这里讲的是后端分页,即实用limit.性能较好,一般均用这种源码下载地址:https://git.oschina.ne ...

  9. 162. Find Peak Element(二分查找 )

      A peak element is an element that is greater than its neighbors. Given an input array where num[i] ...

  10. Educational Codeforces Round 58 Solution

    A. Minimum Integer 签到. #include <bits/stdc++.h> using namespace std; #define ll long long ll l ...