带权图的Dijkstra算法(贪心策略)单源最短路径和-----数据结构与算法笔记

📖 Dijkstra算法描述

🤔问题描述:
给定带权有向图G = (V,E),V代表图的顶点集,E代表图的边集,其中每条边的权值为非负值。另外还给定了V中的一个顶点,称为源点(所求起始顶点),计算从源点到其他各顶点的最短路径长度(为最短路径上各边权值之和)。
如下有向带权图:
在这里插入图片描述

🌴 Dijkstra的理解

[1] 初始化:先找出从源点到各终点vk的直达路径( v 0 v_0 v0, v k v_k vk),即仅通过一条弧到达的路径。并且将权值设为当前路径的权值(权值长度保存在一个一维数组中 D[] ),否则为;选择:从这些直达路径中找出一条长度最短的路径(v0,u)
[2] 选择:从这些直达路径中找出一条长度最短的路径( v 0 v_0 v0,u);
[3] 更新:对其余各条路径进行适当的调整,若在图中存在弧,若在图中存在弧(u, v k v_k vk),且满足
(v0,u)+ (u,vk) < (v0,vk),则将最小的路径(v0,u,vk)替换(v0,vk)
[4] 重复推导,直到所有的其他顶点被推导完为止。

🍃 Dijkstra的思想(贪心选择)

🔥 按路径长度递增次序产生最短的路径;
1️⃣ 设置两个一维数组P[MAX_VERTEX_NUM],D[MAX_VERTEX_NUM], P[]存放从起始顶点当前到指定顶点所已经访问的顶点的最短路径的前驱节点,D[i] 的每个分量表示当前所找到的从源点到每个终点的最短路径的长度,它的初始态为:若从源点到 v j v_j vj 有直达的弧边,则为该弧边的权值,否则 D[i] 为无 ∞
在这里插入图片描述
此时的D[i]路径长度值为源点到 v j v_j vj 的最短路径,为(v,vj);
2️⃣ 增设一个一维数组flag[MAX_VERTEX_NUM], 此数组实际存放长度为节点数,当flag[i] = 1代表了源点到顶点 v j v_j vj的最短路径已经被访问。
3️⃣ 算法步骤:

  1. 设带权领接矩阵arcs表示此有向带权图,arcs[i][j]表示弧<vi,vj>上的权值,若不存在则设为,用S代表已找到从v出发的最短路径的终点的集合,它的初始状态为空。接下来从v出发到图中上其余顶点(终点) v i v_i vi可能到达的最短路径长度的初值为:
    在这里插入图片描述
  2. 选择 v i v_i vi使得:
    在这里插入图片描述 v i v_i vi为当前求得的一条从v出发的最短路径终点,令:S = S ∪{j}
  3. 修改从v出发的集合V-S 上任一顶点 v k v_k vk可达的最短路径长度,如果:
    D[j] + arcs[j][k] < D[k]
    则修改D[k]的值:D[k] = D[j] + arcs[j][k]
    4.重复(2),(3)步骤n-1次(少了源点的步骤)

📝 总体设计

//存储结构选择
typedef struct ArcCell
{
	VRType adj;    //边权值
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

typedef struct 
{
	VRType	vexs[MAX_VERTEX_NUM];		//顶点向量
	AdjMatrix 	arcs;		//邻接矩阵
	int vexnum, arcnum;		//图的当前顶点数和弧数
} MGraph;

//函数
bool CreateDNG(MGraph& G);
int LocateVex(MGraph G, VertexType v);
void PrintDNG(MGraph G);
void ShortPath_DIJ(MGraph G, int v0, int P[], int D[]);

📝 详细设计

//迪杰斯特拉算法
/* v0: 单源节点起始顶点
	P[]: 单源节点v0到其余节点的最短路径的一堆数组
	D[]: 顶点v到其他顶点的最短距离的数组
*/
void ShortPath_DIJ(MGraph G, int v0, int P[], int D[])
{
	int i, j, k;
	int min;
	int tmp;
	int flag[MAX_VERTEX_NUM];      
	// flag[i]=1表示源点v0到顶点vi的最短路径已经访问
	// 初始化
	for (i = 0; i < G.vexnum; i++)
	{
		flag[i] = 0;          // 顶点i的最短路径未被访问
		P[i] = 0;         
		D[i] = G.arcs[v0][i].adj; // 顶点i的最短路径为源点v0到顶点vi的权值
	}

	// 对源点自身进行初始化
	flag[v0] = 1;
	D[v0] = 0;

	// 遍历n-1次;每次找出一个顶点的最短路径;
	for (i = 1; i < G.vexnum; i++)
	{
		// 寻找当前最小的路径;
		// 在未获取最短路径的顶点中,找到离v0最近的顶点
		min = INFINITY;
		//开始寻找v0与当前所有能直达的最短路径顶点,遍历数组D[]找出最小路径
		for (j = 0; j < G.vexnum; j++)
		{
			if (flag[j] == 0 && D[j] < min)
			{
				min = D[j];
				k = j;
			}
		}
		// 标记k顶点为已经获取到最短路径
		flag[k] = 1;

		// 修正当前最短路径,使用贪心策略对当前已经加入进来的顶点在D数组的最短路径进行更新
		for (j = 0; j < G.vexnum; j++)
		{
			tmp = (G.arcs[k][j].adj == INFINITY ? INFINITY : (min + G.arcs[k][j].adj)); 
			if (flag[j] == 0 && (tmp < D[j]))
			{
				D[j] = tmp;
				P[j] = k;
			}
		}
	}
}

🍋 源码

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
#define INFINITY INT_MAX 	//最大值无边为∞,对角线为0,反之为权值
#define MAX_VERTEX_NUM 20   //最大顶点数

typedef int VRType;
typedef int VertexType;
typedef struct ArcCell
{
	VRType adj;    //边权值
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

typedef struct 
{
	VRType	vexs[MAX_VERTEX_NUM];		//顶点向量
	AdjMatrix 	arcs;		//邻接矩阵
	int vexnum, arcnum;		//图的当前顶点数和弧数
} MGraph;

bool CreateDNG(MGraph& G);
int LocateVex(MGraph G, VertexType v);
void PrintDNG(MGraph G);
void ShortPath_DIJ(MGraph G, int v0, int P[], int D[]);

//定位
int LocateVex(MGraph G, VertexType v)
{
	int i;
	for (i = 0; i < G.vexnum; i++)
		if (G.vexs[i] == v) return i;
	return -1;
}

//构建有向网
bool CreateDNG(MGraph& G)
{
	cout << "请输入当前顶点数和弧数(空格隔开):";
	cin >> G.vexnum >> G.arcnum;
	int i, j, k;
	int v1, v2, w;		///弧尾和弧头及权值 
	for (i = 0; i < G.vexnum; i++)
	{
		cout << "请输入第" << (i + 1) << "个顶点的信息(name):";
		cin >> G.vexs[i];
	}

	cout << endl;
	//初始化领接矩阵
	for (i = 0; i < G.vexnum; i++)
		for (j = 0; j < G.vexnum; j++)
		{
			G.arcs[i][j].adj = { INFINITY };
		}

	//对于有向边的确定以及权值的确定
	for (k = 0; k < G.arcnum; k++)
	{
		cout << "请输入第" << (k + 1) << "条边的起点和终点以及权值(空格隔开):";
		cin >> v1 >> v2 >> w;
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		if (i == -1 || j == -1) return false;
		else
			G.arcs[i][j].adj = w;
	}
	return true;
}

//打印有向网
void PrintDNG(MGraph G)
{
	int i, j;
	cout <<  "有向网的顶点为:" << endl;
	for (i = 0; i < G.vexnum; i++)
		cout << "V" << G.vexs[i] << " ";
	cout << endl;

	cout << "有向网的领接矩阵为:" << endl;
	cout << "\t";
	for (i = 0; i < G.vexnum; i++)
	{
		cout << setw(7) << "V" << G.vexs[i];
	}

	cout << endl;
	for (i = 0; i < G.vexnum; i++)
	{
		cout << "\n" << setw(7) << "V" << G.vexs[i];
		for ( j = 0; j < G.vexnum; j++)
		{
			if (G.arcs[i][j].adj == INT_MAX && i != j) cout << setw(8) << "∞";
			else if(i == j) 	cout << setw(8) << "0";
			else
				cout << setw(8) << G.arcs[i][j].adj;
		}
		cout << endl;
	}
}

//迪杰斯特拉算法
/* v0: 单源节点起始顶点
	P[]: 单源节点v0到其余节点的最短路径的一堆数组
	D[]: 顶点v0到其他顶点的最短距离的数组
*/
void ShortPath_DIJ(MGraph G, int v0, int P[], int D[])
{
	int i, j, k;
	int min;
	int tmp;
	int flag[MAX_VERTEX_NUM];      
	// flag[i]=1表示源点v0到顶点vi的最短路径已经访问
	// 初始化
	for (i = 0; i < G.vexnum; i++)
	{
		flag[i] = 0;          // 顶点vi的最短路径未被访问
		P[i] = 0;              
		D[i] = G.arcs[v0][i].adj; // 顶点i的最短路径为源点v0到顶点vi的权值
	}

	// 对源点v0自身进行初始化
	flag[v0] = 1;
	D[v0] = 0;

	// 遍历n-1次;每次找出一个顶点的最短路径;
	for (i = 1; i < G.vexnum; i++)
	{
		// 寻找当前最小的路径;
		// 在未获取最短路径的顶点中,找到离v0最近的顶点k
		min = INFINITY;
		//开始寻找v0与当前所有能直达的最短路径顶点,遍历数组D[]找出最小路径
		for (j = 0; j < G.vexnum; j++)
		{
			if (flag[j] == 0 && D[j] < min)
			{
				min = D[j];
				k = j;
			}
		}
		// 标记顶点vk为已经获取到最短路径
		flag[k] = 1;

		// 修正当前最短路径,使用贪心策略对当前已经加入进来的顶点在D数组的最短路径进行更新
		for (j = 0; j < G.vexnum; j++)
		{
			tmp = (G.arcs[k][j].adj == INFINITY ? INFINITY : (min + G.arcs[k][j].adj)); // 防止溢出
			if (flag[j] == 0 && (tmp < D[j]))
			{
				D[j] = tmp;
				P[j] = k;
			}
		}
	}
}

int main()
{
	MGraph G;
	CreateDNG(G);
	PrintDNG(G);

	int P[MAX_VERTEX_NUM] = {0};
	int D[MAX_VERTEX_NUM] = {0};
	int num;
	cout << "请输入所求的单源起始顶点(1~6):";
	cin >> num;
	ShortPath_DIJ(G, num-1, P, D);

	cout << endl;

	cout << "源点V" << num << "到各顶点的最短路径长度为:" << endl;
	for (int i = 0; i < G.vexnum; i++) 
	{
		if (D[i] == INFINITY)
			cout << "V" << G.vexs[num - 1] << " -> V" << G.vexs[i] << " = " << "∞" << endl;
		else cout << "V" << G.vexs[num - 1] << " -> V" << G.vexs[i] << " = " << D[i] << endl;
	}

    system("pause");
    return 0;
}

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
贪心算法单源路径指的是在一个加权有向图中,从给定的源点到所有其他顶点的最路径问题。Dijkstra算法是最常用的贪心算法之一,用于解决单源路径问题。其基本思想是从源点开始,每次选择当前最路径的顶点,并更新其相邻顶点的距离,直到所有顶点都被遍历。具体步骤如下: 1.初始化:将源点到所有顶点的距离初始化为无穷大,源点到自身的距离为0。 2.选择当前最路径的顶点:从未确定最路径的顶点中选择距离最的顶点。 3.更新相邻顶点的距离:对于当前选定的顶点,更新其相邻顶点的距离,如果经过当前顶点到达相邻顶点的距离比原来的距离更,则更新距离。 4.重复步骤2和3,直到所有顶点都被遍历。 以下是一个使用Dijkstra算法求解单源路径的Python代码示例: ```python import heapq def dijkstra(graph, start): # 初始化距离 distances = {vertex: float('infinity') for vertex in graph} distances[start] = 0 # 使用堆来存储顶点和距离 pq = [(0, start)] while pq: # 取出距离最小的顶点 current_distance, current_vertex = heapq.heappop(pq) # 如果当前距离大于已知最距离,则跳过 if current_distance > distances[current_vertex]: continue # 更新相邻顶点的距离 for neighbor, weight in graph[current_vertex].items(): distance = current_distance + weight if distance < distances[neighbor]: distances[neighbor] = distance heapq.heappush(pq, (distance, neighbor)) return distances ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小王桐学

谢谢,只求点赞哟

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值