图算法 -- Dijkstra Algorithm

本文详细介绍了如何使用C语言实现Dijkstra算法,并通过实例解释了算法的执行过程及核心思想,帮助读者理解如何在图论问题中寻找最短路径。
<h2 align="center"><strong><em>The Dijkstra Algorithm</em></strong></h2><p align="center"><a target=_blank href="mailto:eryar@163.com"><strong><em>eryar</em></strong>@<strong><em>163</em></strong>.<strong><em>com</em></strong></a> </p><p><strong>摘要</strong>:本文用<strong><em>C</em></strong>实现了图的最短路径<strong><em>Dijkstra</em></strong>算法,并将自己理解该算法的方式与大家分享下,若有错误之处,欢迎指正。 </p><p><strong>关键字</strong>:图、最短路径、<strong><em>Graph</em></strong>、<strong><em>Dijkstra</em></strong> </p><h3>一、引言 <strong><em>Introduction</em></strong></h3><p>对图<strong><em>G</em></strong>中的每一条边<strong><em>e</em></strong>都赋以一个实数<strong><em>w</em></strong>(<strong><em>e</em></strong>),则<strong><em>G</em></strong>连同它边上的权称为赋权图。赋权图经常出现在图论的实际应用问题中,边上的权(<strong><em>Weight</em></strong>)可以表示各种实际意义,如在输送网络中,权可以表示两地的距离,可以表示运输的时间,还可以表示运输的费用等。许多最优化问题相当于在一个赋权图中找出某类具有最小(或最大)权的子图。例如,给出一个连接各城镇的铁路网,要找出一条给定两个城镇间的最短路线。这个问题的图论模型建立如下:以顶点代表城镇,边代表城镇间的铁路线,权表示直接相连的城镇之间的铁路距离,得到一个赋权图,即网络<strong><em>N</em></strong>。 </p><p>本文讨论带权的有向图,并称路径上的第一个顶点为源点(<strong><em>Source</em></strong>),最后一个顶点为终点(<strong><em>Destination</em></strong>)。 </p><p align="center"><a target=_blank href="http://www.cppblog.com/images/cppblog_com/eryar/WindowsLiveWriter/Dijkstra_11DE9/Dijkstra_Animation_4.gif"><img style="DISPLAY: block; FLOAT: none; MARGIN-LEFT: auto; MARGIN-RIGHT: auto" title="Dijkstra_Animation" alt="Dijkstra_Animation" src="http://www.cppblog.com/images/cppblog_com/eryar/WindowsLiveWriter/Dijkstra_11DE9/Dijkstra_Animation_thumb_1.gif" width="283" height="222" /></a> </p><h3>二、算法理解 <strong><em>Understanding the Algorithm</em></strong></h3><p><strong><em>Dijkstra</em></strong>算法描述为:假设用带权邻接矩阵来表示带权有向图。首先引进一个辅助向量<strong><em>D</em></strong>,它的每个分量<strong><em>D</em></strong>[<strong><em>i</em></strong>]表示当前所找到的从始点<strong><em>v</em></strong>到每个终点<strong><em>Vi</em></strong>的最短路径。它的初始状态为:若两顶点之间有弧,则<strong><em>D</em></strong>[<strong><em>i</em></strong>]为弧上的权值;否则置<strong><em>D</em></strong>[<strong><em>i</em></strong>]为无穷大。 </p><p>u 找到与源点<strong><em>v</em></strong>最近的顶点,并将该顶点并入最终集合<strong><em>S</em></strong>; </p><p>u 根据找到的最近的顶点更新从源点<strong><em>v</em></strong>出发到集合<strong><em>V</em></strong>-<strong><em>S</em></strong>上可达顶点的最短路径; </p><p>u 重复以上操作。 </p><p><a target=_blank href="http://www.cppblog.com/images/cppblog_com/eryar/WindowsLiveWriter/Dijkstra_11DE9/clip_image004_2.jpg"><img style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title="" border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/eryar/WindowsLiveWriter/Dijkstra_11DE9/clip_image004_thumb.jpg" width="243" height="234" /></a> </p><p>图<strong><em>1</em></strong> 带权有向图 </p><p>以前总是认为<strong><em>Dijkstra</em></strong>算法可以用来求从源点到指定终点的最短路径,导致总不能抓住算法的中心思想。现在认为把握<strong><em>Dijkstra</em></strong>的算法要点为: </p><p>u <strong><em>Dijkstra</em></strong>提出了一个按路径长度递增的次序产生最短路径的算法; </p><p>u 每次循环都可以得到一个从源点到某个顶点的最短路径,某个即不是确定的一个; </p><p>以带权有向图<strong><em>1</em></strong>为例说明<strong><em>Dijkstra</em></strong>算法的执行过程:假设源点为<strong><em>v0</em></strong>,则初始状态时源点到其它各顶点的距离为: </p><table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td valign="top" width="103"><p>源点 终点</p></td><td valign="top" width="86"><p><strong><em>v1</em></strong></p></td><td valign="top" width="95"><p><strong><em>v2</em></strong></p></td><td valign="top" width="95"><p><strong><em>v3</em></strong></p></td><td valign="top" width="95"><p><strong><em>v4</em></strong></p></td><td valign="top" width="95"><p><strong><em>v5</em></strong></p></td></tr><tr><td valign="top" width="103"><p><strong><em>v0</em></strong></p></td><td valign="top" width="86"><p>∽</p></td><td valign="top" width="95"><p><strong><em>10</em></strong></p></td><td valign="top" width="95"><p>∽</p></td><td valign="top" width="95"><p><strong><em>30</em></strong></p></td><td valign="top" width="95"><p><strong><em>100</em></strong></p></td></tr></tbody></table><p>由上表可知,与源点<strong><em>v0</em></strong>最近的顶点为<strong><em>v2</em></strong>,距离为<strong><em>10</em></strong>。 </p><p>将<strong><em>v2</em></strong>加入到最终顶点集合<strong><em>S</em></strong>中。 </p><p>再根据<strong><em>v2</em></strong>更新从源点到其它顶点的最短距离,即从<strong><em>v0</em></strong>-<strong><em>v2</em></strong>-<strong><em>v3</em></strong>的距离为<strong><em>60</em></strong><∽,所以将<strong><em>v0</em></strong>到<strong><em>v3</em></strong>的距离更新为<strong><em>60</em></strong>,如下表所示: </p><table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td valign="top" width="103"><p>源点 终点</p></td><td valign="top" width="86"><p><strong><em>v1</em></strong></p></td><td valign="top" width="95"><p><strong><em>v2</em></strong></p></td><td valign="top" width="95"><p><strong><em>v3</em></strong></p></td><td valign="top" width="95"><p><strong><em>v4</em></strong></p></td><td valign="top" width="95"><p><strong><em>v5</em></strong></p></td></tr><tr><td valign="top" width="103"><p><strong><em>v0</em></strong></p></td><td valign="top" width="86"><p>∽</p></td><td valign="top" width="95"><p><strong><em><del>10</del></em></strong><del></del></p></td><td valign="top" width="95"><p><strong><em>60</em></strong></p></td><td valign="top" width="95"><p><strong><em>30</em></strong></p></td><td valign="top" width="95"><p><strong><em>100</em></strong></p></td></tr></tbody></table><p>由上表可知,与源点<strong><em>v0</em></strong>次近的顶点为<strong><em>v4</em></strong>,距离为<strong><em>30</em></strong>。 </p><p>将<strong><em>v4</em></strong>加入到最终顶点集合<strong><em>S</em></strong>中; </p><p>再根据<strong><em>v4</em></strong>更新从源点到其它顶点的最短距离。即从<strong><em>v0</em></strong>-<strong><em>v4</em></strong>-<strong><em>v3</em></strong>的距离为<strong><em>50</em></strong><<strong><em>60</em></strong>,所以将<strong><em>v0</em></strong>到<strong><em>v3</em></strong>的距离更新为<strong><em>50</em></strong>;从<strong><em>v0</em></strong>-<strong><em>v4</em></strong>-<strong><em>v5</em></strong>的距离为<strong><em>90</em></strong><<strong><em>100</em></strong>,所以将<strong><em>v0</em></strong>到<strong><em>v5</em></strong>的距离更新为<strong><em>90</em></strong>。 </p><table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td valign="top" width="103"><p>源点 终点</p></td><td valign="top" width="86"><p><strong><em>v1</em></strong></p></td><td valign="top" width="95"><p><strong><em>v2</em></strong></p></td><td valign="top" width="95"><p><strong><em>v3</em></strong></p></td><td valign="top" width="95"><p><strong><em>v4</em></strong></p></td><td valign="top" width="95"><p><strong><em>v5</em></strong></p></td></tr><tr><td valign="top" width="103"><p><strong><em>v0</em></strong></p></td><td valign="top" width="86"><p>∽</p></td><td valign="top" width="95"><p><strong><em><del>10</del></em></strong><del></del></p></td><td valign="top" width="95"><p><strong><em>50</em></strong></p></td><td valign="top" width="95"><p><strong><em><del>30</del></em></strong><del></del></p></td><td valign="top" width="95"><p><strong><em>90</em></strong></p></td></tr></tbody></table><p>重复以上操作…… </p><p>直到最终集合包含了所有的顶点。</p>
/*Dijkstra求单源最短路径 2010.8.26*/
#include<fstream>
#include <iostream>
#include<stack>
#define M 100
#define N 100
using namespace std;

typedef struct node
{
	int matrix[N][M];      //邻接矩阵 
	int n;                 //顶点数 
	int e;                 //边数 
}MGraph;

void DijkstraPath(MGraph g, int *dist, int *path, int v0)   //v0表示源顶点 
{
	int i, j, k;
	bool *visited = (bool *)malloc(sizeof(bool)*g.n);
	for (i = 0; i<g.n; i++)     //初始化 
	{
		if (g.matrix[v0][i]>0 && i != v0)
		{
			dist[i] = g.matrix[v0][i];
			path[i] = v0;     //path记录最短路径上从v0到i的前一个顶点 
		}
		else
		{
			dist[i] = INT_MAX;    //若i不与v0直接相邻,则权值置为无穷大 
			path[i] = -1;
		}
		visited[i] = false;
		path[v0] = v0;
		dist[v0] = 0;
	}
	visited[v0] = true;
	for (i = 1; i<g.n; i++)     //循环扩展n-1次 
	{
		int min = INT_MAX;
		int u;
		for (j = 0; j<g.n; j++)    //寻找未被扩展的权值最小的顶点 
		{
			if (visited[j] == false && dist[j]<min)
			{
				min = dist[j];
				u = j;
			}
		}
		visited[u] = true;
		for (k = 0; k<g.n; k++)   //更新dist数组的值和路径的值 
		{
			if (visited[k] == false && g.matrix[u][k]>0 && min + g.matrix[u][k]<dist[k])
			{
				dist[k] = min + g.matrix[u][k];
				path[k] = u;
			}
		}
	}
}

void showPath(int *path, int v, int v0)   //打印最短路径上的各个顶点 
{
	stack<int> s;
	int u = v;
	while (v != v0)
	{
		s.push(v);
		v = path[v];
	}
	s.push(v);
	while (!s.empty())
	{
		cout << s.top() << " ";
		s.pop();
	}
}

int main(int argc, char *argv[])
{
	int n, e;     //表示输入的顶点数和边数 
	fstream cin;
	cin.open("in16.txt");
	while (cin >> n >> e&&e != 0)
	{
		int i, j;
		int s, t, w;      //表示存在一条边s->t,权值为w
		MGraph g;
		int v0;
		int *dist = (int *)malloc(sizeof(int)*n);
		int *path = (int *)malloc(sizeof(int)*n);
		for (i = 0; i<N; i++)
		for (j = 0; j<M; j++)
			g.matrix[i][j] = 0;
		g.n = n;
		g.e = e;
		for (i = 0; i<e; i++)
		{
			cin >> s >> t >> w;
			g.matrix[s][t] = w;
		}
		cin >> v0;        //输入源顶点 
		DijkstraPath(g, dist, path, v0);
		for (i = 0; i<n; i++)
		{
			if (i != v0)
			{
				showPath(path, i, v0);
				cout << dist[i] << endl;
			}
		}
	}
	return 0;
}

源码地址: https://pan.quark.cn/s/a4b39357ea24 欧姆龙触摸屏编程软件MPTST 5.02是专门为欧姆龙品牌的工业触摸屏而研发的编程解决方案,它赋予用户在直观界面上构建、修改以及排错触摸屏应用程序的能力。 该软件在工业自动化领域具有不可替代的地位,特别是在生产线监视、设备操控以及人机互动系统中发挥着核心作用。 欧姆龙MPTST(Machine Process Terminal Software Touch)5.02版本配备了多样化的功能,旨在应对不同种类的触摸屏项目要求。 以下列举了若干核心特性:1. **图形化编程**:MPTST 5.02采用图形化的编程模式,允许用户借助拖拽动作来设计屏幕布局,设定按钮、滑块、指示灯等组件,显著简化了编程流程,并提升了工作效率。 2. **兼容性**:该软件能够适配欧姆龙的多个触摸屏产品线,包括CX-One、NS系列、NJ/NX系列等,使用户可以在同一个平台上完成对不同硬件的编程任务。 3. **数据通信**:MPTST 5.02具备与PLC(可编程逻辑控制器)进行数据交互的能力,通过将触摸屏作为操作界面,实现生产数据的显示与输入,以及设备状态的监控。 4. **报警与事件管理**:软件中集成了报警和事件管理机制,可以设定多种报警标准,一旦达到预设条件,触摸屏便会展示对应的报警提示,助力操作人员迅速做出响应。 5. **模拟测试**:在设备实际连接之前,MPTST 5.02支持用户进行脱机模拟测试,以此验证程序的正确性与稳定性。 6. **项目备份与恢复**:为了防止数据遗失,MPTST 5.02提供了项目文件的备份及还原功能,对于多版本控制与团队协作具有显著价值。 7. **多语言支持**:针对全球化的应...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值