C++小练习—Dijkstra

1、问题描述

给定一个有向带权图 G=(V E) ,其中每条边的权是一个非负实数。另外,给定 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] 具有最小值的顶点 t t 就是集合 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;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值