复习:最短路径

2023-11-11

一、基本概念

  • 最短路径:在非网图中,最短路径是指两顶点之间经历的边数最少的路径;在网图中,最短路径是指两顶点之间经历的边上权值之和最少的路径。
  • 源点:路径上的第一个顶点。
  • 终点:路径上最后一个顶点。

二、Dijkstra算法(只适用于简单路径,不适合回路)
Dijkstra算法用于求单元点最短路径问题,给定有向网图G=(V,E)和源点v属于V,求v到G中其余各个顶点的最短路径。
①基本思路:

  1. 将顶点集合V分成两个集合,集合S存放源点v和已经确定最短路径的顶点,另一个集合V-S存放未确定最短路径的顶点。
  2. 初始化:S只包含源点v,对vi属于V-S,待定路径表为从源点v到vi的有向边。
  3. 在待定路径表中找到当前最短路径,v…vk,将vk加入S,对vi属于V-S,将路v…vkvi与待定路径表中从源点v到vi的最短路径相比较,去路径长度较小者为当前最短路径。

②存储结构:

  1. 图的存储结构:邻接矩阵
  2. 辅助数组dist[n]:元素dist[i]表示当前所找到的从源头v到终点vi的最短路径的长度。(dist[i] = min{dist[i],dist[k]+edge[k][i])
  3. 辅助数组path[n]:元素path[i]是一个字符串,表示当前从源点v到终点vi的最短路径。(没有弧则为空串)
void Dijkstra(int v)//从源点v出发
{
	int i,k,num,dist[MaxSize];
	string path[MaxSize];
	for(i = 0 ;i<vertexNum ; i++)//初始化数组dist和path
	{
		dist[i] = edge[v][i];
		if(dist[i]!=100)//假设100为边上权的最大值
			path[i] = vertex[v]+vertex[i];//vertex数组存储的是顶点,+为字符串连接操作
		else
			path[i] = "";//没有边可达,即无穷,则为空串
	}
	
	for(num = 1 ; num<vertexNum ; num++)//扫描V-S中的所有顶点
	{
		k = Min(dist,vertexNum);//在dist数组中(路径列表)找到最小值并返回其下标(注意要越过0值)
		cout<<path[k]<<dist[k];
		for(i = 0 ; i<vertexNum ; i++)//插入新加入的k顶点,修改dist和path数组
		{
			if(dist[i]>dist[k]+edge[k][i])
			{
				dist[i] = dist[k]+edge[k][i];
				path[i] = path[k]+vertex[i];//+为字符串连接操作
			}
		}
		dist[k] = 0;//将顶点k加入到集合S中
	}
}
			

Dijkstra算法的时间复杂度为O(n^2),有两个规律:

  1. 最短路径是按路长度递增的次序产生的。
  2. 最短路径上可能经过已产生终点的顶点。

实例:以邻接矩阵为存储结构,实现有向带权图的最短路径算法Dijkstra,完整代码如下:

#include <iostream>
using namespace std;

const int MaxSize = 10;           //图中最多顶点个数
int visited[MaxSize]={0};
const int MAX = 1000; 

 
struct element			//改进:使用结构体数组代替lowcast数组以及adjvex数组
{
	int lowcost, adjvex;
};

int MinEdge(element *e,int vertexNum);

template <class DataType>
class MGraph
{
public:
	MGraph(DataType a[ ], int n, int e);    //构造函数,建立具有n个顶点e条边的图
	~MGraph( ) { }                     //析构函数为空
	void DFSTraverse(int v);              //深度优先遍历图
	void BFSTraverse(int v);               //广度优先遍历图
	void Dijkstra(int v);
private:
    DataType vertex[MaxSize];          //存放图中顶点的数组
    int edge[MaxSize][MaxSize];          //存放图中边的数组
    int vertexNum, edgeNum;             //图的顶点数和边数
};

template <class DataType>
MGraph<DataType>::MGraph(DataType a[ ], int n, int e)
{
	int i, j, k ,x;
	vertexNum = n;
	edgeNum = e;
	for (i = 0; i < vertexNum; i++)
		vertex[i] = a[i];
	for (i = 0; i < vertexNum; i++)
		for (j = 0; j < vertexNum; j++)
			edge[i][j] = MAX;
	for (k = 0; k < edgeNum; k++)
	{
		cout << "请输入两个边顶点的序号:";
		cin >> i >> j;			//输入边依附的两个顶点的编号 
		 
		cout << "请输入边的权值:"; 
		cin >> x;
		edge[i][j] = x;		//置边的标志为1 
		edge[j][i] = x;		//无向图 边是相通的 
	}
}

template <class DataType>
void MGraph<DataType>::DFSTraverse(int v)
{
	cout << vertex[v];
	visited[v] = 1;
	for (int j = 0; j < vertexNum; j++)
	{
		if (edge[v][j] != MAX && visited[j] == 0)DFSTraverse(j); //存在与v相连的j点且j点未被访问过 则进一步遍历j点 
	}
}

template <class DataType>
void MGraph<DataType>::BFSTraverse(int v)
{
	int w, j, Q[MaxSize];
	int front = -1, rear = -1;
	cout << vertex[v];
	visited[v] = 1;
	Q[++rear] = v;		//v点入队 
	while (front != rear)
	{
		w = Q[++front];	//Q出队值 w 
		for (j = 0; j < vertexNum; j++)//遍历所有可能与w相连的点 若有,则输出、标记、入队 
		{
			if (edge[w][j] != MAX && visited[j] == 0)//存在与w点相连的j点且j点未被访问过 则输出j点值 然后标记j点将j点入队 
			{
				cout << vertex[j];
				visited[j] = 1;
				Q[++rear] = j;
			}
		}
	}
}

int Min(int dist[],int vertexNum)
{
	int min = 100;
	for(int i=0 ; i<vertexNum ; i++)
	{
		if(dist[i]<min)
			min = dist[i];
	}
	return min;
 } 

template<typename DataType>
void MGraph<DataType>::Dijkstra(int v)//从源点v出发
{
	int i,k,num,dist[MaxSize];
	string path[MaxSize];
	for(i = 0 ;i<vertexNum ; i++)//初始化数组dist和path
	{
		dist[i] = edge[v][i];
		if(dist[i]!=100)//假设100为边上权的最大值
			path[i] = vertex[v]+vertex[i];//vertex数组存储的是顶点,+为字符串连接操作
		else
			path[i] = "";//没有边可达,即无穷,则为空串
	}
	
	for(num = 1 ; num<vertexNum ; num++)//扫描V-S中的所有顶点
	{
		k = Min(dist,vertexNum);//在dist数组中(路径列表)找到最小值并返回其下标(注意要越过0值)
		cout<<path[k]<<dist[k];
		for(i = 0 ; i<vertexNum ; i++)//插入新加入的k顶点,修改dist和path数组
		{
			if(dist[i]>dist[k]+edge[k][i])
			{
				dist[i] = dist[k]+edge[k][i];
				path[i] = path[k]+vertex[i];//+为字符串连接操作
			}
		}
		dist[k] = 0;//将顶点k加入到集合S中
	}
}

int main( )
{
	char ch[]={'A','B','C','D','E'};
	MGraph<char> MG(ch, 5, 7);
	for (int i=0; i<MaxSize; i++)
		visited[i]=0;
	cout<<"深度优先遍历序列是:";
	MG.DFSTraverse(0);
	cout<<endl;
	for (int i=0; i<MaxSize; i++)
		visited[i]=0;
    cout<<"广度优先遍历序列是:";
	MG.BFSTraverse(0);
	cout<<endl;
	cout<<"从顶点"<<ch[0]<<"到各终点的最短路径分别是:"<<endl;
    MG.Dijkstra(0);
	cout<<endl;
    system("pause");
}


二、Floyd算法(地铁路线规划)
Floyd算法用于求每一对顶点之间的最短路径问题,给定带权有向图G=(V,E),对任意顶点vi和vj(i不等于j),求顶点vi到vj的最短路径。
①基本思想:

  1. 假设从vi到vj是最短路径,然后进行n次试探。
  2. 比较vi vj和vi vk vj的路径长度,去长度较短者作为vi到vj中间顶点的编号不大于0的最短路径。

②存储结构:

  1. 图的存储结构:邻接矩阵
  2. 辅助数组dist[n][n]:存放在迭代过程中求得的最短路径。(dist_-1[i][j] = edge[i][j];dist_k[i][j] = min{dist_k[i][j],dist_k[i][k]+dist_k-1[k][j]})->插入顶点k后更新路径的长度
  3. 辅助数组path[n][n]:在迭代中存放vi到vj的最短路径,初始为“vi vj”
void Floyd()
{
	int i,j,k,dist[MaxSize][MaxSize];
	string path[MaxSize][MaxSize];
	for(i = 0 ; i<vertexNum ; i++)//初始化矩阵dist和path
	{
		for(j = 0 ; j<vertexNum ; j++)
		{
			dist[i][j] = edge[i][j];
			if(dist[i][j]!=100)//假设权值最大为100
				path[i][j] = vertex[i]+vertex[j];
			else
				path[i][j] = "";
		}
	}

	for(k = 0 ; k<vertexNum ; k++)//n个顶点进行迭代,n个顶点分别插入到二维矩阵(path)的路径中看是否更新路径
	{
		for(i = 0 ; i<vertexNum ; i++)//二维矩阵的两层循环
		{
			for(j = 0 ; j<vertexNum ; j++)
			{
				if(dist[i][k]+dist[k][j]<dist[i][j])
				{
					dist[i][j] = dist[i][k]+dist[k][j];
					path[i][j] = path[i][k]+paht[k][j];
				}
			}
		}
	}
}

n个顶点更新迭代n次,插入顶点k时,插入到除k行k列外的其他路径中才有意义。
实例:医院选址问题(《数据结构》课本P211)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

复习:最短路径 的相关文章

  • 文举论金:黄金原油全面走势分析策略指导。

    市场没有绝对 涨跌没有定势 所以 对市场行情的涨跌平衡判断就是你的制胜法宝 欲望 有句意大利谚语 让金钱成为我们忠心耿耿的仆人 否则 它就会成为一个专横跋扈的主人 空头 多头都能赚钱 唯有贪心不能赚 是你掌控欲望还是欲望掌控你 古人云 不积
  • MVCC 实现原理

    这里是CS大白话专场 让枯燥的学习变得有趣 没有对象不要怕 我们new一个出来 每天对ta说不尽情话 好记性不如烂键盘 自己总结不如收藏别人 在讲解 MVCC 之前先来看一下 MySQL 中事务的四种隔离级别 读未提交 一个事务可以读到另一
  • ChatGPT生成内容很难脱离标准化,不建议用来写留学文书

    ChatGPT无疑是23年留学届的热门话题 也成为了不少留学生再也离不开的万能工具 从总结文献 润色论文 给教授写email似乎无所不能 各大高校对于学生使用ChatGPT的态度也有所不同 例如 哈佛大学教育代理院长 Anne Harrin

随机推荐

  • Unity游戏编程-——迷宫巡逻兵

    文章目录 游戏设计要求 程序设计要求 基本思路分析 模式基础 架构设计 关键模块 遇到的问题 资源地址 游戏设计要求 创建一个地图和若干巡逻兵 使用动画 每个巡逻兵走一个3 5个边的凸多边型 位置数据是相对地址 即每次确定下一个目标位置 用
  • 字节跳动(飞书)产品测试实习生一面

    下面面试问题的顺序记不清了 所以没按面试官问的顺序写 1 性能测试 2 黑盒和白盒 3 用过飞书吗 知道飞书的产品流程吗 4 谈谈你简历上写的项目 提到购物车功能 仔细讲讲 5 学过软件工程管理 说说整个软件的项目管理流程 6 看有服役的经
  • Linux系统调用指南

    Linux系统调用指南 文章是转载 但是我在后面的案例加了不少注解并debug了 如有疑问 留言交流 其实我也不懂 原文链接 blog packagecloud io https zcfy cc article the definitive
  • QTcpSocket发送数据和自定义数据

    在网络应用中 有时候我们会遇到这样的问题 用TCP不断的接收和发送不同类型的数据 数据大小 格式都不相同 起初看了qt的例子 按照例子写的程序效果相当的不好 尤其是在连续发送大数据的时候 接收端根本无法判断数据是否完整了 也不知道什么时候取
  • 基于VMD-LSTM-IOWA-RBF的碳排放混合预测研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码实现 1 概述 二氧化碳排放力争于2030年前达到峰值 努
  • uni-app checkbox全选的实现

    界面是这样的 需求 点击全选按钮上述全部选中 再次点击全部取消 解决方案 在js的data里面定义一个allCheck data return allCheck false 上面商品的的checkbox都一样的配置
  • window 无法访问docker_无法在windows中访问docker端口

    我在dockerfile中写了脚本来运行我的角度项目 It将创建集装箱 什么时候我正在运行我的容器我无法在浏览器中访问主机和端口 它说连接被拒绝了 我用windows机器 用工具箱运行docker 我的容器 gt 81471a6fbd35
  • php爬虫简单入门

    前些日子有点空闲就做了一个简单的爬虫 爬取了知乎50W条数据 因为知乎有测试流量过大 导致经常有验证码 本人图片验证码没有研究所以每次都是手动输入 有兴趣的小伙伴可以做个自动识别验证码就可以无限采取了 爬虫使用了curl public fu
  • spring嵌套事务,try-catch事务处理

    spring 事务总结 前置条件 表Teacher 别名 A 表Student 别名 B 分别插入 A中启动事务 B中不启动事务 testDemo01调用方法开启事务 testDemo01开启事务 A中insert中开启事务 调用执行 A中
  • 蓝牙协议介绍

    1 广播 ADV Advertising 1 1 BLE 报文结构 BLE引入access address 概念 用来指明接收者身份 概 其中 0x8E89BED6 这个access address 比较特殊 它表示要发给周边所有设备 即广
  • msys2 安装gcc g++ 命令

    pacman S base devel gcc vim
  • 常见设计模式的解析和实现(C++)之九—Decorator模式

    作用 动态地给一个对象添加一些额外的职责 就增加功能来说 Decorator模式相比生成子类更为灵活 UML结构图 抽象基类 1 Component 定义一个对象接口 可以为这个接口动态地添加职责 2 Decorator 维持一个指向Com
  • 优秀的Windows密码抓取工具

    优秀的工具如下 01 Mimikatz 简介 Mimikat是一个法国人写的轻量级调试器 Mimikat可以从内存中提取纯文本密码 hash PIN码和kerberos票证 mimikatz还可以执行哈希传递 票证传递或构建Golden票证
  • ESP8266 hspi的调试

    这一两个礼拜基本上都在爬这个坑 功夫不负有心人 终于搞定了 其实非常简单 以为这个东西有多么的复杂 其实不是这样的 被一些网上博主给误导了 8266端我用的是 ESP8266 NONOS SDK 3 0 examples periphera
  • 使用ANT打包Android应用

    转自 http blog csdn net liuhe688 article details 6679879 大家好 今天来分享一下如何使用ANT打包Android应用 通常我们习惯用eclipse来开发Android程序 它会自动帮我们打
  • 架构妄想:AJAX + REST

    原文地址 http www infoq com cn news 2011 10 ArchitecturalMirages William Vambenepe的最新文章 AJAX REST是最新的架构妄想 让我们回想起了一个具有15年历史的架
  • 粒子滤波器的Matlab实现

    前言 粒子滤波器相较于卡尔曼滤波器或者UKF无迹卡尔曼滤波器而言 可以表达强非线性的变换且无需假设后验分布为高斯分布 在描述多峰分布时具有非常大的优势 粒子滤波器被广泛的应用于机器人系统中 如著名的Gmapping算法便是在粒子滤波器的基础
  • 怎么往阿里云服务器传东西

    https zhidao baidu com question 2075785777388289788 html
  • Unity C# 委托——事件,Action,Func的作用和区别

    参考视频 三分钟彻底搞懂委托 事件 Action Func的作用和区别 哔哩哔哩 bilibili 委托关系图 Delegate 定义两个模板 一个可以传参一个不可以传参 模板 1 public delegate void xxxxx in
  • 复习:最短路径

    一 基本概念 最短路径 在非网图中 最短路径是指两顶点之间经历的边数最少的路径 在网图中 最短路径是指两顶点之间经历的边上权值之和最少的路径 源点 路径上的第一个顶点 终点 路径上最后一个顶点 二 Dijkstra算法 只适用于简单路径 不