小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
Dijkstra理论模型
作为大型RPG游戏寻路是一个很重要的环节,在A*出现之前叱咤风云的算法还是当之无愧的属于迪杰斯特拉算法,那么,什么是迪杰斯特拉算法呢?迪杰斯特拉算法是一位荷兰计算机大佬迪杰斯特拉1959年提出的一种思想,它是最典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。最大之特点是以起始点为中心向外层层扩展,一直到终点,也就是说它的轨迹是从内到外的螺旋形轨迹。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容的详细简介,当然,我不是计算机专业,我是电气工程及其自动化转行过来的,目前在职,IT方面是自学来的,所以说数据结构,图论以及运筹学都是自己业余时间看资料学来的。废话不多说了,我先贴个我干刚刚画的图大家看下。↓↓
这是一个无向图,啥意思?就是没有具体方向的图啊!看图↑,这上边有5个点7条边。首先,我们找到一个点,我们按照顺序从a点开始。
设:A点坐标是A(-,0),我们把其余与A点相关的点到A点的距离计算一下,根据路径上的权值计算出长度和图中的一样先记录数据,B(A,3)和D(A,7)。
好了现在我们可以确定B点到A的距离最短所以确定边AB,此时B的权重为3,然后从B出发,找出所有与B相连的点把各个路径上的权重与B相加。得到D(B,3+2)和C(B,3+4)。现在我们确定一下第二条边BD吧,D的权值为5,权值最小,∴第三个点应该是D点。
根据这个思路我们继续走,以后的点都是这么找,与D点相连的有C,E两个点,我们计算出来的长度是C(D,10)和E(E,5+4)。此时C的权重为10了,而C为7,
∴应该选择边BC而不是DC。现在还剩下最后一个点E,从C到E是(C,13),从D到E是(d,6)。
∴选择路径D-E,
∴最终路径是A-B-D-E。
下面附上我写的代码实现的Dijkstra算法的流程:↓↓
struct MGraph
{
public int[,] edges;
public int n, e;
}
定义结构体里边放一个二维数组和顶点变量n和变数变量e
const int MAX_V = 100;
const int INF = 32767;
MGraph mg = new MGraph();
/// <summary>
/// U集合
/// </summary>
private List<int> uList = new List<int>();
/// <summary>
/// S集合
/// </summary>
private Sset sset = new Sset();
public GraphClass()
{
mg.edges = new int[MAX_V, MAX_V];
}
/// <summary>
/// 创建图的矩阵
/// </summary>
/// <param name="n">顶点的个数</param>
/// <param name="e">边数</param>
/// <param name="a">图的矩阵存储</param>
public void CreateMGraph(int n, int e, int[,] a)
{
mg.n = n;
mg.e = e;
for (int i = 0; i < mg.n; i++)
{
uList.Add(i);
for (int j = 0; j < mg.n; j++)
{
mg.edges[i, j] = a[i, j];
}
}
}
※创建S集合和U集合,这里有必要说明一下S集合和U集合,初始的时候S集合只包含远点,所以S = v,v = 0,U集合是包含除了v以外其他的顶点,U中顶点u距离为边上的权。然后从U集合中选取一个距离v最小的顶点n,把n加到S集合里,这时该选定的距离就是v到n的最短路径了。
继续,以n为最新考虑的中间点,修改U集合中各顶点的距离;若从原点v到顶点n经过n顶点的距离比原来不经过n顶点的距离要短,则要修改顶点n的距离值,修改之后的距离值的顶点n的距离加上边上的权。
之后,上述的步骤重复进行……因为这个S集合有点特殊,我把它封装了一个类,如下图↓↓
/// <summary>
/// S集合
/// </summary>
public class Sset
{
public List<int> list;
public Dictionary<string, int> dic;
public Sset()
{
list = new List<int>();
dic = new Dictionary<string, int>();
}
}
S集合的构造函数中包含一个集合和一个链表。
下面写一个函数把矩阵图给打印出来↓↓!
/// <summary>
/// 输出图的矩阵
/// </summary>
/// <returns></returns>
public string DispMGraph()
{
string str = string.Empty;
for (int i = 0; i < mg.n; i++)
{
if (i == 0)
str += " A B C D E F\r\n";
for (int j = 0; j < mg.n; j++)
{
if (j == 0)
str = (ZM)i + " ";
str += string.Format("{0,-4}", mg.edges[i, j].ToString());
}
str += "\r\n";
}
return str;
}
注:ZM是一个枚举,里边包含了6个顶点A,B,C,D,E,F的编号依次是0,1,2,3,4,5。下面贴上Dijkstra核心算法Dijkstra函数↓↓
public void Dijkstra()
{
sset.list.Add(0);
sset.dic.Add("0", 0);
sset.dic.Add("0-0", 0);
int max = 100000;
int uListPosition = 0;
string path = string.Empty;
while (uList.Count > 1)
{
foreach (KeyValuePair<string,int> item in sset.dic)
{
string[] temp = item.Key.Split('-');
int last = Convert.ToInt32(temp[temp.Length - 1]);
for (int i = 0; i < uList.Count; i++)
{
if (!temp.Contains(uList[i].ToString()))
{
if (mg.edges[last, uList[i]] != -1 && mg.edges[last, uLi
{
max = mg.edges[last, uList[i]];
uListPosition = i;
path = item.Key;
}
}
}
}
sset.list.Add(uList[uListPosition]);
sset.dic.Add(path + "-" + uList[uListPosition], max + sset.dic[path]
uList.Remove(uList[uListPosition]);
max = 100000;
}
foreach (KeyValuePair<string,int> item in sset.dic)
{
string[] temp = item.Key.Split('-');
string consoleString = "";
foreach (string itemStr in temp)
{
consoleString += (ZM)(Convert.ToInt32(itemStr)) + "-";
}
consoleString = consoleString.Remove(consoleString.LastIndexOf('-'))
Console.WriteLine(consoleString + "距离:" + item.Value);
}
}
遍历S集合,实现的思路是上述标“※”的部分。然后我们来到Main函数,写几个点的坐标,设顶点数是6,边数是9.将矩阵图和迪杰斯特拉路径打印出来~
class Program
{
static void Main(string[] args)
{
int n = 6, en = 9;
/// <summary>
/// -1表示不可达
/// </summary>
int[,] a = new int[,]
{
{0,6,3,-1,-1,-1},
{6,0,2,5,-1,-1},
{3,2,0,3,4,-1},
{-1,5,3,0,2,3},
{-1,-1,4,2,0,5},
{-1,-1,-1,3,5,0}
};
GraphClass graphClass = new GraphClass();
graphClass.CreateMGraph(n, en, a);
Console.WriteLine(graphClass.DispMGraph());
graphClass.Dijkstra();
Console.ReadKey();
}
}
这样我们的流程就走完了,按下F5打开控制台调试一下↓↓
下面附上我的Dijkstra算法的源码百度云网盘地址:↓↓链接:pan.baidu.com/s/1nvcJwu9 密码:emt5)
这就是迪杰斯特拉算法C#的编程思想,前提大家要有一些数学中解析几何的基本知识才能破解这个难题,风暴洋PABLO.Y祝大家学习愉快。