Dijkstra算法手写记录(1)

8.2重新温习一些最短路径的基本算法:

提供数据,运行的时候直接粘贴,不需要输入别的值:

5 0 5 4 10 -1 -1 0 -1 3 2 -1 -1 0 2 3 -1 -1 2 0 -1 -1 -1 1 5 0

图形是这样的:
在这里插入图片描述

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int MAXN = 10;
const int INF = 32767;
int edge[MAXN][MAXN];   //邻接矩阵
int Vex_num;   //顶点个数
int path[MAXN];  //记录节点前驱,也就是存储最短路径
int Serve[MAXN];    //已经求出最短路径的节点数组

int dist[MAXN];    //表示从源点到各个顶点的路径长度,在dijkstra算法里面由于是单源求最短,所以只需要一维数组,
//而在floyd里面,需要求多源最短路径,那个时候需要二维数组


void Print_Map()   //打印地图
{
	cout << "顶点关系如下:\n";
	cout << " ";
	for (int i = 0; i < Vex_num; i++)
	{
		printf("%3d  ", i);
	}
	cout << "\n";
	for (int i = 0; i < Vex_num; i++)
	{
		cout << i;
		for (int j = 0; j < Vex_num; j++)
		{
			printf("% 5d  ", edge[i][j]);
		}
		cout << endl;
	}
	cout << "\n\n";
}

void Find_path()   //找最短路径
{
	cout << "现在输出从源点出发到其它所有顶点的最短路径:\n";
	for (int i = Vex_num - 1; i > 0; i--)
	{
		int k = i;  //找从k到0的最短路径
		cout << "从顶点" << "0" << "到顶点" << i << "的路径为:\n";
		cout << k;
		while (path[k] != k)
		{
			k = path[k];   //k节点的前一个节点赋值给k,直到path[0]==0;
			cout << "->"<<k;
		}
		cout << "最短路径长度:" << dist[i] << endl;
	}
}

void Dijkstra()  //求出源点到其它任意点的最短路径,但是注意,源点是固定的,
{
	//思路:(1)从顶点集合中找到距离源点最近的一个点
	int min_Vex = 0x3f3f3f3f;  
	int target_min_Vex;   //标记找到离源点最近的点的编号
	Serve[0] = 1;    //这个程序以编号0的点为源点
	for (int i = 0; i < Vex_num; i++)
	{
		if (Serve[i] != 1)   //首先要确保这个点(要找的离源点最近的点)没有被放入最短路径集合
		{
			if (dist[i] < min_Vex)
			{
				min_Vex = dist[i];
				target_min_Vex = i;
			}
				
		}
	}
	Serve[target_min_Vex] = 1;    //将其加入最短路径集合Serve
	//思路:(2)找到当前离源点最短路径的点,且将其加入serve集合,那么此时我们知道两件事情;
	//1,这个被加入到Serve的点到源点的路径就是最后这个点到源点的最短路径,为什么会这样,可以用反证法来说明
	//2,由于新点加入,这个时候需要更新dist[],因为新的点的加入使某些没有连通的边产生变化,


	for (int i = 0; i < Vex_num; i++)
	{
		if (Serve[i]==0)   //修改没有加入serve的点,加入的已经是最短路径,不能动了。
		{
			if (edge[target_min_Vex][i] < INF && dist[target_min_Vex] + edge[target_min_Vex][i] < dist[i])
			{
				dist[i] = dist[target_min_Vex] + edge[target_min_Vex][i];
				path[i] = target_min_Vex;   //i的前驱节点是target,也就是新加入的节点
			}
		}
	}
	Find_path();
}


int main()
{
	//以编号为0的点做源点
	//首先要将顶点之间的边关系表示出来,可直接初始化。也可以手动输入
	//首先确定有多少个顶点
	
	cout << "输入顶点个数:\n";
	cin >> Vex_num;
	for (int i = 0; i < Vex_num; i++)
		for (int j = 0; j < Vex_num; j++)
			edge[i][j] = INF;
	memset(dist, -1, sizeof(dist));
	for (int i = 0; i < Vex_num; i++)    //依次输入每个顶点的邻接顶点和他们之间的距离
	{
		int i_to_j;   //点i到点j的距离
		for (int j = 0; j < Vex_num; j++)
		{
			cout << "顶点" << i << "到顶点" << j << "的距离是";
			cin >> i_to_j;
			if (i_to_j!=-1)   //i到j的边如果不连通,就是无穷大,输入用-1来表示
			{
				edge[i][j] = i_to_j;
			}
		}
		if (i == 0)  //初始化dist[]
		{
			for (int j = 0; j < Vex_num; j++)
			{
				dist[j] = edge[i][j];
				if (edge[i][j] != -1)
					path[j] = i;
				else
					path[j] = -1;
			}

		}
	}

	Print_Map();   //打印地图

	Dijkstra();   //用dijkstra算法求单源最短路径
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值