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. HDU_5517_Triple

    Triple Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  2. socketserver源码解析和协程版socketserver

    来,贴上一段代码让你仰慕一下欧socketserver的魅力,看欧怎么完美实现多并发的魅力 client import socket ip_port = ('127.0.0.1',8009) sk = ...

  3. mrbs - 初识

    一.mrbs mrbs:(meeting room booking system)会议室预订系统 二.效果 三.models from django.db import models # Create ...

  4. Spring源码解析(五)循环依赖问题

    引言 循环依赖就是多个类之间互相依赖,比如A依赖B,B也依赖A,如果日常开发中我们用new的方式创建对象,这种循环依赖就会导致不断的在创建对象,导致内存溢出. Spring是怎么解决循环依赖的问题的? ...

  5. java基础知识面试题(1-40)

    1.面向对象的特征有哪些方面?答:面向对象的特征主要有以下几个方面:- 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面.抽象只关注对象有哪些属性和行为,并不关注这些 ...

  6. python2.7多线程的批量操作远程服务器

    #!/usr/bin/env python #-*- coding:utf-8 -*- #多线程批量远程执行一条命令 # made in china import threading import s ...

  7. 2.1 The Object Model -- Classes and Instances(类和实例)

    一.Defining Classes(定义类) 1. 定义一个新的Ember类,调用Ember.Object上的extend()方法: example:定义了一个含有say()方法的新的Person类 ...

  8. node核心:异步流程控制

    Node.js的异步是整个学习Node.js过程中重中之重. 1)异步流程控制学习重点 2)Api写法:Error-first Callback 和 EventEmitter 3)中流砥柱:Promi ...

  9. 图像处理(二十一)基于数据驱动的人脸卡通动画生成-Siggraph Asia 2014

    http://blog.csdn.net/garfielder007/article/details/50582018 在现实生活中,我们经常会去评价一个人,长得是否漂亮.是不是帅哥美女,然而如何用五 ...

  10. Web前端学习笔记之前端跨域知识总结

    0x00 前言 相信每一个前端er对于跨域这两个字都不会陌生,在实际项目中应用也是比较多的.但跨域方法的多种多样实在让人目不暇接.老规矩,碰到这种情况,就只能自己总结一篇博客,作为记录. 0x01 什 ...