C++小练习—Dijkstra

本文详细阐述了如何通过一种算法求解从源点到所有其他顶点的最短路径长度,涉及数据结构设计、初始化、路径搜索及更新等关键步骤,并通过代码实现展示了算法的具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、问题描述

™给定一个有向带权图 G=(VE),其中每条边的权是一个非负实数。另外,给定V中的一个顶点,称为源点。计算从源点到所有其它各个顶点的最短路径长度,这里的路径长度是指路径上经过的所有边上的权值之和。

2、算法设计
1)算法思想
按各个顶点与源点之间路径长度的递增次序,生成源点到各个顶点的最短路径的方法,即先求出长度最短的一条路径,再参照它求出长度次短的一条路径,依此类推,直到从源点到其它各个顶点的最短路径全部求出为止。
2)算法步骤
步骤1:设计合适的数据结构。带权邻接矩阵C,即如果< u, x >E,令C[u][x]=<u, x >的权值,否则,C[u][x]=无穷;采用数组dist来记录从源点到其它顶点的最短路径长度;采用数组p来记录最短路径;
步骤2:初始化。令集合S={u},对于集合V-S中的所有顶点x,设置dist[x]=C[u][x];如果顶点i与源点相邻,设置p[i]=u,否则p[i]=-1
步骤3:在集合V-S中依照贪心策略来寻找使得dist[x]具有最小值的顶点tt就是集合V-S中距离源点u最近的顶点。
步骤4:将顶点t加入集合S中,同时更新集合V-S
步骤5:如果集合V-S为空,算法结束;否则,转步骤6
步骤6:对集合V-S中的所有与顶点t相邻的顶点x,如果dist[x]>dist[t]+C[t][x],则dist[x]=dist[t]+C[t][x]并设置p[x]=t。转步骤3

3、代码
#include<iostream>
#include<vector>

using namespace std;

const int Maxval=0x7FFFFFFF;//无穷大
const int Node=5;//图的节点个数

int C[Node][Node]={//设置图的节点间的权值,本身到本身为0
	{0,8,32,Maxval,Maxval},
	{12,0,16,17,Maxval},
	{Maxval,29,0,Maxval,13},
	{Maxval,21,Maxval,0,7},
	{Maxval,Maxval,27,19,0}
};

int dist[Node-1]={Maxval};//记录从原节点到其他节点的最短路径长度,初始值设为无穷大
int p[Node]={-2};//记录最短路径

vector<int> S,VmS;


void Init(int V[])
{
	S.push_back(V[0]);//初始化集合S和V-S,S集合中只包含起始节点,其余节点在V-S中
	for(int i=1;i<Node;++i)
	{
		VmS.push_back(V[i]);
	}
	for(auto it1=VmS.begin();it1!=VmS.end();++it1)//容器中存储的数据是节点的编号
	{
		dist[(*it1)]=C[0][*it1];
		if(dist[(*it1)]!=Maxval)
		{
			p[(*it1)]=0;
		}
		else
			p[(*it1)]=-1;
	}
}

void PrintS()//打印选取节点的顺序
{
	cout<<"节点加入S的顺序:";
	for(auto it=S.begin();it!=S.end();++it)
		cout<<*it<<" ";
	cout<<endl;
}

void PrintP(int p[])//打印最短路径
{
	for(auto it=S.begin();it!=S.end();++it)
	{
		cout<<*it<<"的最短路径为:";
		for(int i=1;i<=(*it);++i)
		{
			if(i==1)
				cout<<p[i]<<"->";
			else if(p[i]!=-1&&p[i]!=p[i-1])
				cout<<p[i]<<"->";
		}
		cout<<*it<<endl;
	}
}

void dijkstra(vector<int> &,vector<int> &)
{
	int mindist=Maxval,t;
	for(auto it=VmS.begin();it!=VmS.end();++it)
	{
		if(dist[(*it)]<mindist)//找出距离最小的点
		{
			mindist=dist[(*it)];
			t=(*it);
		}
	}
	auto it=VmS.begin();//删除V-S集合中的节点
	while(it!=VmS.end())
	{
		if((*it)==t)
		{
			VmS.erase(it);
			break;
		}
		else ++it;
	}
	S.push_back(t);//将该节点加入到S集合中

	if(!VmS.empty())
	{
		for(auto it=VmS.begin();it!=VmS.end();++it)
		{
			if(C[t][*it]!=Maxval)
			{
				if(dist[(*it)]>dist[t]+C[t][(*it)])
				{
					dist[(*it)]=dist[t]+C[t][(*it)];
					p[*it]=t;
				}
			}
		}
		dijkstra(S,VmS);
	}
	else
	{
			PrintS();
	}
}

int main()
{
	int V[Node]={-1};//存储节点编号
	for(int i=0;i<Node;++i)//节点编号初始化
	{
		V[i]=i;
	}
	Init(V);
    dijkstra(S,VmS);
	PrintP(p);
	system("pause");
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值