经典算法题每日演练——第十七题 Dijkstra算法
或许在生活中,经常会碰到针对某一个问题,在众多的限制条件下,如何去寻找一个最优解?可能大家想到了很多诸如“线性规划”,“动态规划”
这些经典策略,当然有的问题我们可以用贪心来寻求整体最优解,在图论中一个典型的贪心法求最优解的例子就莫过于“最短路径”的问题。
一:概序
从下图中我要寻找V0到V3的最短路径,你会发现通往他们的两点路径有很多:V0->V4->V3,V0->V1->V3,当然你会认为前者是你要找的最短
路径,那如果说图的顶点非常多,你还会这么轻易的找到吗?下面我们就要将刚才我们那点贪心的思维系统的整理下。

二:构建
如果大家已经了解Prim算法,那么Dijkstra算法只是在它的上面延伸了下,其实也是很简单的。
1.边节点
这里有点不一样的地方就是我在边上面定义一个vertexs来记录贪心搜索到某一个节点时曾经走过的节点,比如从V0贪心搜索到V3时,我们V3
的vertexs可能存放着V0,V4,V3这些曾今走过的节点,或许最后这三个节点就是我们要寻找的最短路径。
1 #region 边的信息
2 /// <summary>
3 /// 边的信息
4 /// </summary>
5 public class Edge
6 {
7 //开始边
8 public int startEdge;
9
10 //结束边
11 public int endEdge;
12
13 //权重
14 public int weight;
15
16 //是否使用
17 public bool isUse;
18
19 //累计顶点
20 public HashSet<int> vertexs = new HashSet<int>();
21 }
22 #endregion
2.Dijkstra算法

首先我们分析下Dijkstra算法的步骤:
有集合M={V0,V1,V2,V3,V4}这样5个元素,我们用
TempVertex表示该顶点是否使用。
Weight表示该Path的权重(默认都为MaxValue)。
Path表示该顶点的总权重。
①. 从集合M中挑选顶点V0为起始点。给V0的所有邻接点赋值,要赋值的前提是要赋值的weight要小于原始的weight,并且排除已经访问过
的顶点,然后挑选当前最小的weight作为下一次贪心搜索的起点,就这样V0V1为挑选为最短路径,如图2。
②. 我们继续从V1这个顶点开始给邻接点以同样的方式赋值,最后我们发现V0V4为最短路径。也就是图3。
。。。
③. 最后所有顶点的最短路径就这样求出来了 。
1 #region Dijkstra算法
2 /// <summary>
3 /// Dijkstra算法
4 /// </summary>
5 public Dictionary<int, Edge> Dijkstra()
6 {
7 //收集顶点的相邻边
8 Dictionary<int, Edge> dic_edges = new Dictionary<int, Edge>();
9
10 //weight=MaxValue:标识没有边
11 for (int i = 0; i < graph.vertexsNum; i++)
12 {
13 //起始边
14 var startEdge = i;
15
16 dic_edges.Add(startEdge, new Edge() { weight = int.MaxValue });
17 }
18
19 //取第一个顶点
20 var start = 0;
21
22 for (int i = 0; i < graph.vertexsNum; i++)
23 {
24 //标记该顶点已经使用过
25 dic_edges[start].isUse = true;
26
27 for (int j = 1; j < graph.vertexsNum; j++)
28 {
29 var end = j;
30
31 //取到相邻边的权重
32 var weight = graph.edges[start, end];
33
34 //赋较小的权重
35 if (weight < dic_edges[end].weight)
36 {
37 //与上一个顶点的权值累加
38 var totalweight = dic_edges[start].weight == int.MaxValue ? weight : dic_edges[start].weight + weight;
39
40 if (totalweight < dic_edges[end].weight)
41 {
42 //将该顶点的相邻边加入到集合中
43 dic_edges[end] = new Edge()
44 {
45 startEdge = start,
46 endEdge = end,
47 weight = totalweight
48 };
49
50 //将上一个边的节点的vertex累加
51 dic_edges[end].vertexs = new HashSet<int>(dic_edges[start].vertexs);
52
53 dic_edges[end].vertexs.Add(start);
54 dic_edges[end].vertexs.Add(end);
55 }
56 }
57 }
58
59 var min = int.MaxValue;
60
61 //下一个进行比较的顶点
62 int minkey = 0;
63
64 //取start邻接边中的最小值
65 foreach (var key in dic_edges.Keys)
66 {
67 //取当前 最小的 key(使用过的除外)
68 if (min > dic_edges[key].weight && !dic_edges[key].isUse)
69 {
70 min = dic_edges[key].weight;
71 minkey = key;
72 }
73 }
74
75 //从邻接边的顶点再开始找
76 start = minkey;
77 }
78
79 return dic_edges;
80 }
81 #endregion
总的代码:复杂度很烂O(N2)。。。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.IO;
using System.Threading.Tasks; namespace ConsoleApplication2
{
public class Program
{
public static void Main()
{
Dictionary<int, string> dic = new Dictionary<int, string>(); MatrixGraph graph = new MatrixGraph(); graph.Build(); var result = graph.Dijkstra(); Console.WriteLine("各节点的最短路径为:"); foreach (var key in result.Keys)
{
Console.WriteLine("{0}", string.Join("->", result[key].vertexs));
} Console.Read();
}
} #region 定义矩阵节点
/// <summary>
/// 定义矩阵节点
/// </summary>
public class MatrixGraph
{
Graph graph = new Graph(); public class Graph
{
/// <summary>
/// 顶点信息
/// </summary>
public int[] vertexs; /// <summary>
/// 边的条数
/// </summary>
public int[,] edges; /// <summary>
/// 顶点个数
/// </summary>
public int vertexsNum; /// <summary>
/// 边的个数
/// </summary>
public int edgesNum;
} #region 矩阵的构建
/// <summary>
/// 矩阵的构建
/// </summary>
public void Build()
{
//顶点数
graph.vertexsNum = 5; //边数
graph.edgesNum = 6; graph.vertexs = new int[graph.vertexsNum]; graph.edges = new int[graph.vertexsNum, graph.vertexsNum]; //构建二维数组
for (int i = 0; i < graph.vertexsNum; i++)
{
//顶点
graph.vertexs[i] = i; for (int j = 0; j < graph.vertexsNum; j++)
{
graph.edges[i, j] = int.MaxValue;
}
} //定义 6 条边
graph.edges[0, 1] = graph.edges[1, 0] = 2;
graph.edges[0, 2] = graph.edges[2, 0] = 5;
graph.edges[0, 4] = graph.edges[4, 0] = 3;
graph.edges[1, 3] = graph.edges[3, 1] = 4;
graph.edges[2, 4] = graph.edges[4, 2] = 5;
graph.edges[3, 4] = graph.edges[4, 3] = 2; }
#endregion #region 边的信息
/// <summary>
/// 边的信息
/// </summary>
public class Edge
{
//开始边
public int startEdge; //结束边
public int endEdge; //权重
public int weight; //是否使用
public bool isUse; //累计顶点
public HashSet<int> vertexs = new HashSet<int>();
}
#endregion #region Dijkstra算法
/// <summary>
/// Dijkstra算法
/// </summary>
public Dictionary<int, Edge> Dijkstra()
{
//收集顶点的相邻边
Dictionary<int, Edge> dic_edges = new Dictionary<int, Edge>(); //weight=MaxValue:标识没有边
for (int i = 0; i < graph.vertexsNum; i++)
{
//起始边
var startEdge = i; dic_edges.Add(startEdge, new Edge() { weight = int.MaxValue });
} //取第一个顶点
var start = 0; for (int i = 0; i < graph.vertexsNum; i++)
{
//标记该顶点已经使用过
dic_edges[start].isUse = true; for (int j = 1; j < graph.vertexsNum; j++)
{
var end = j; //取到相邻边的权重
var weight = graph.edges[start, end]; //赋较小的权重
if (weight < dic_edges[end].weight)
{
//与上一个顶点的权值累加
var totalweight = dic_edges[start].weight == int.MaxValue ? weight : dic_edges[start].weight + weight; if (totalweight < dic_edges[end].weight)
{
//将该顶点的相邻边加入到集合中
dic_edges[end] = new Edge()
{
startEdge = start,
endEdge = end,
weight = totalweight
}; //将上一个边的节点的vertex累加
dic_edges[end].vertexs = new HashSet<int>(dic_edges[start].vertexs); dic_edges[end].vertexs.Add(start);
dic_edges[end].vertexs.Add(end);
}
}
} var min = int.MaxValue; //下一个进行比较的顶点
int minkey = 0; //取start邻接边中的最小值
foreach (var key in dic_edges.Keys)
{
//取当前 最小的 key(使用过的除外)
if (min > dic_edges[key].weight && !dic_edges[key].isUse)
{
min = dic_edges[key].weight;
minkey = key;
}
} //从邻接边的顶点再开始找
start = minkey;
} return dic_edges;
}
#endregion
}
#endregion
}

经典算法题每日演练——第十七题 Dijkstra算法的更多相关文章
- 经典算法题每日演练——第十一题 Bitmap算法
原文:经典算法题每日演练--第十一题 Bitmap算法 在所有具有性能优化的数据结构中,我想大家使用最多的就是hash表,是的,在具有定位查找上具有O(1)的常量时间,多么的简洁优美, 但是在特定的场 ...
- 经典算法题每日演练——第八题 AC自动机
原文:经典算法题每日演练--第八题 AC自动机 上一篇我们说了单模式匹配算法KMP,现在我们有需求了,我要检查一篇文章中是否有某些敏感词,这其实就是多模式匹配的问题. 当然你也可以用KMP算法求出,那 ...
- 经典算法题每日演练——第六题 协同推荐SlopeOne 算法
原文:经典算法题每日演练--第六题 协同推荐SlopeOne 算法 相信大家对如下的Category都很熟悉,很多网站都有类似如下的功能,“商品推荐”,"猜你喜欢“,在实体店中我们有导购来为 ...
- 经典算法题每日演练——第七题 KMP算法
原文:经典算法题每日演练--第七题 KMP算法 在大学的时候,应该在数据结构里面都看过kmp算法吧,不知道有多少老师对该算法是一笔带过的,至少我们以前是的, 确实kmp算法还是有点饶人的,如果说红黑树 ...
- 经典算法题每日演练——第十一题 Bitmap算法 (转)
http://www.cnblogs.com/huangxincheng/archive/2012/12/06/2804756.html 在所有具有性能优化的数据结构中,我想大家使用最多的就是hash ...
- 经典算法题每日演练——第十六题 Kruskal算法
原文:经典算法题每日演练--第十六题 Kruskal算法 这篇我们看看第二种生成树的Kruskal算法,这个算法的魅力在于我们可以打一下算法和数据结构的组合拳,很有意思的. 一:思想 若存在M={0, ...
- 经典算法题每日演练——第十四题 Prim算法
原文:经典算法题每日演练--第十四题 Prim算法 图论在数据结构中是非常有趣而复杂的,作为web码农的我,在实际开发中一直没有找到它的使用场景,不像树那样的频繁使用,不过还是准备 仔细的把图论全部过 ...
- 【算法导论】单源最短路径之Dijkstra算法
Dijkstra算法解决了有向图上带正权值的单源最短路径问题,其运行时间要比Bellman-Ford算法低,但适用范围比Bellman-Ford算法窄. 迪杰斯特拉提出的按路径长度递增次序来产生源点到 ...
- codeforces水题100道 第二十七题 Codeforces Round #172 (Div. 2) A. Word Capitalization (strings)
题目链接:http://www.codeforces.com/problemset/problem/281/A题意:将一个英文字母的首字母变成大写,然后输出.C++代码: #include <c ...
随机推荐
- CallContext和多线程
前一段时间正好要在某个网页程序上开一个多线程调用多个组件的尝试,这些组件是有其他团队开发的(如:印度/俄罗斯),所以修改它们的代码看起来是不太现实的,但是,令人恼火的是他们的代码中大量的用到了AppC ...
- Heibernate 入门笔记(一)---第一个demo
最近在学heibernate,是看马士兵老师的视频学的,在这里总结一下,做点笔记.关于heibernate的优点,大家可以在网上 百度,这里不做赘述,直接讲怎么使用heibernate 步骤一:新建项 ...
- c#中 uint--byte[]--char[]--string相互转换汇总
原文:c#中 uint--byte[]--char[]--string相互转换汇总 在在做一些互操作的时候往往需要一些类型的相互转换,比如用c#访问win32api的时候往往需要向api中传入DWOR ...
- 对ESB概念的理解(转)
http://www.ibm.com/developerworks/cn/webservices/0811_magy_esb/ 什么是 ESB?ESB 严格来说不是某一个产品,而是一种框架,设计模式. ...
- YT新人之巅峰大决战03
题目链接 Problem Description Now give you two integers n m, you just tell me the m-th number after radix ...
- sqlite3触发器的使用
研究了一下osx下dock中应用的存储,位于~/Library/Application Support/Dock/下一个比較名字比較长的db文件里,之前简单的介绍过osx launchpad图标的删除 ...
- 使用hadoop命令rcc生成Record 一个简单的方法来实现自己的定义writable对象
hadoop 的bin文件夹以下一个rcc命令,网上介绍非常少.看了一下源代码.发现能够用来生成 java和c++的hadoop Record 类代码,比起自己直接实现writable 接口.简单非常 ...
- poj 1466 Girls and Boys (最大独立集)
链接:poj 1466 题意:有n个学生,每一个学生都和一些人有关系,如今要你找出最大的人数.使得这些人之间没关系 思路:求最大独立集,最大独立集=点数-最大匹配数 分析:建图时应该是一边是男生的点, ...
- 寒假了,想深入学习c++
本来在图书馆借了好几本属,但是,自己没有经验,借的书都太深奥,看不懂,哎,桑心!
- 在Ceph创建虚拟机的过程改进分析
作为个人学习笔记分享.有不论什么问题欢迎交流! 近期在Gerrit中看到一个change:https://review.openstack.org/#/c/94295/ , 它主要是对当前在Ceph中 ...