单源最短路径(Dijkstra)C语言

笔记 专栏收录该内容
7 篇文章 0 订阅

Dijkstra算法

dijkstra是建立在广度优先遍历算法上面
只不过 相较于广度优先遍历 加入了许多的限制
上题
在这里插入图片描述
这题是求从起点0到点6的最短路径和长度

Dijkstra算法需要维护一个距离数组D 数组长度是节点长度 这个距离数组是用来记录每一个点到起始点0的距离 这个数组同时也能来确定下一个访问点

Dijkstra算法还有一个要求作为扩散点被访问了的节点不能被再次访问
比如 第一次用0作为起始点 并且用D记录了各点的距离之后 起始点0就不能被访问 可以才用标记法对其进行标记

我处理这道题使用的是 邻接矩阵用来存储信息
使用的一般的Dijkstra算法
(还有一种是Dijkstra+优先级队列)
声明一些信息 和 初始化邻接矩阵

#include<stdio.h>
#define MAX 20
#define INF 65535
static int Graph[MAX][MAX];//邻接矩阵
static int n;//用来记录顶点数
//颜色用来标记访问情况
static const int WHITE = 0;//未被访问
static const int BLACK = 1;//被访问
static int path[MAX];//记录路径
int main()
{	
	int u, k, c,m,i,j;
	scanf(" %d", &n);//确定顶点数
	for (i = 0; i < n; i++)
		for (j = 0; j < n; j++)
			Graph[i][j] = INF;
	for (i = 0; i < n; i++)
	{
		scanf(" %d %d", &u, &k);//u为顶点 k为度数
		path[i] = -1;//初始化路径为-1
		for (j = 0; j < k; j++)
		{
			scanf("%d %d ", &c, &m);//c为相邻点  m为长度
			Graph[u][c] = m;//在邻接矩阵里面记录权值
		 }
	 }
	dijkstra();
	return 0;
}

初始化完成之后就进行Dijkstra算法

static void dijkstra() 
{ 
	int d[MAX];//Dijkstra维护的数组
	int color[MAX];//颜色数组 用来标记
	int minv;
	int i, u;
	for (i = 0; i < n; i++)
	{
		d[i] = INF;
		color[i] = WHITE; //全部初始化
	 }
	d[0] = 0;//设置起始点 本题为0
	while (1)
	{
		minv = INF;//设置初值 方便后续找到最短长度
		u = -1;//用于结束判断的标记 和 记录最小点
		for (i = 0; i < n; i++)//遍历所有的点 
		{//从中选取出到起始点0最小的值 并且要未被访问
			if (minv > d[i] && color[i] != BLACK)
			{
				minv = d[i];
				u = i;
			 }
		 }
		if (u == -1) 
			break;
		color[u] = BLACK; //标记成被访问状态
		for (i = 0; i < n; i++)
		{	//遍历相邻节点 
			if (color[i] != BLACK && Graph[u][i] != INF)
			{
	// 如果相邻节点d[i]到距离大于经过从u通过的距离d[i]+Graph[u][i]
	//表明可以相邻节点i可以有短的路径 然后设置成通过u的路径
				if (d[i] > d[u] + Graph[u][i])  
					d[i] = d[u] + Graph[u][i];
			 }
		}
	 }
	 //起始点0到终点6的路径
	printf(" 路径长度:%d\n", d[n - 1]);
	black(0, d[n - 1]);//显示最短路径
}

显示最短路径的节点

static void PrintPath()
{
	int i;
	printf(" 路径\n");
	for (i = 0; i < n; i++)
	{
		if (path[i] == -1) continue;
		printf(" %d\t", i);
	 }
	printf(" %d\n", n - 1);
}

static void black(int i, int length)
{
	int j;
	if (length == 0 && i==6)//节点在6并且同时length为0的情况停止
	{
		PrintPath();
	 }
	else if ( length>0)
	{
		//选定节点 0开始
		path[i] = 0;//如果能够选定当前节点就设置成0
		for (j = 0; j < n; j++)
		{//遍历所有的相邻节点
			if (Graph[i][j] == INF) continue;
			if (length >= Graph[i][j])//如果长度大于Graph[i][j]
			{//说明还有剩余 可以用于下一个节点遍历
				black(j,length-Graph[ i][ j]);
			 }
			path[i] = -1;//回溯 初始化为-1
		 }
	}
}

测试结果
在这里插入图片描述
如果有写的不好地方 还请提出来 谢谢各位观看

  • 0
    点赞
  • 0
    评论
  • 6
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值