单源点最短路径Dijkstra算法

一、Dijkstra算法策略
(1)数据结构
n:城市顶点个数,m:城市间路线的条数。
map[][]:地图对应的带权邻接矩阵。
dist[][]:记录源点u到某个顶点的最短路径长度。
p[]:记录源点到某个顶点的最短路径上的该顶点的前一个顶点(即前驱结点)。
flag[i]:其值为true时说明顶点i 已经加入到集合S,否则顶点i属于集合V-S。
(集合S包含的顶点特点:dist[i]即从源点到顶点i的最短路径长度为最后的最短长度,即最简化;集合V代表全部顶点)

const int N = 100;//初始化城市的个数,可以修改
const int INF = 1e7; //即1*(10^7)无穷大
int map[N][N],dist[N],p[N],n,m;
bool flag[N];

(2)初始化源点u到其他各个顶点的最短路径长度,初始化源点u出边邻结点(即u可直达的其他的顶点t)的前驱为u;

bool flag[n];
for(int i = 1;i <= n;i++)
{
	dist[i] = map[u][i];//初始化源点u到其他各个顶点的最短路径长度
	flag[i] = false;
	if(dist[i] == INF)
		p[i] = -1;
	else
		p[i] = u;
}

(3)初始化集合S,令集合S={u},从源点到u(即u到u)的最短路径为0.

flag[u] = true;//集合S={u}
dist[u] = 0;//从源点到u(即u到u)的最短路径为0

(4)找最小,加入S集合
在集合V-S中寻找距离源点u的距离最短的顶点t,如果找不到t,则说明u=t,可以跳出循环结束;否则,将t加入集合S。

int temp = INF,t = u;
for(int j=1;j<=n;j++)
	if( !flag[j] && dist[t] < temp) // !flag[j]即不在集合S里面的顶点
 	{
 		t = j;  //记录下来
 		temp = dist[t]; //记录最小值,和下一个比较
	}
if(t == u)
	return;
flag[t] = true; //将t加入集合S

(5)借东风(距离源点u的距离最短的顶点是t)
考查集合V-S中源点u到t的邻接点j的距离,即map[t][j]的距离,如果源点u经过t到达j的路径更短,则更新dist[j],即dist[j]=dist[t]+map[t][j];即松弛操作,并记录j的前驱结点t。

for(int j=1;j<=n;j++)
	if( !flag[j] && map[t][j]<INF)
		if(dist[j] > dist[t]+map[t][j])
		{
			dist[j]=dist[t]+map[t][j];
			p[j]=t;
		}

(6)重复(4)~(5),直到结束。

二、代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<Windows.h>
#include<stack>
using namespace std;
const int N = 100;//城市的个数可以修改
const int INF = 1e7;//初始化无穷大
int map[N][N], dist[N], p[N], n, m;//城市的个数n,城市间路线的条数m
bool flag[N];//其值为true时说明顶点i 已经加入到集合S,否则顶点i属于集合V-S。

void Dijkstra(int u)
{
	int i,j;
	for ( i = 1; i <= n; i++)
	{
		dist[i] = map[u][i]; //初始化源点u到其他各个顶点的最短路径长度
		flag[i] = false;
		if (dist[i] == INF)
			p[i] = -1;
		else
			p[i] = u;
	}
	dist[u] = 0;
	flag[u] = true;

	//在集合V-S中寻找距离源点u的距离最短的顶点t,如果找不到t,则说明u=t,可以跳出循环结束;否则,将t加入集合S。
	for ( i = 1; i <= n; i++)
	{
		int temp = INF, t = u;
		for ( j = 1; j <= n;j++)
			if (!flag[j] && dist[j] < temp)
			{
				t = j;
				temp = dist[j];
			}
		if (t == u)
			return;
		flag[t] = true;//将t加入集合S

		/*考查集合V - S中源点u到t的邻接点j的距离,即map[t][j]的距离,
		如果源点u经过t到达j的路径更短,则更新dist[j],即dist[j] = dist[t] + map[t][j];即松弛操作,并记录j的前驱结点t。*/
		for ( j = 1; j <= n; j++)  //距离源点u的距离最短的顶点是t
		{
			if (!flag[j] && dist[j] > dist[t] + map[t][j])
			{
				dist[j] = dist[t] + map[t][j];
				p[j] = t;
			}
		}

	}

}

//显示最短路径上经过了哪些城市
void findpath(int u)
{
	int x;
	int i;
	stack<int> s;//创建一个栈s
	cout << "源点为:" << u << endl;
	for ( i = 1; i <= n; i++)//从源点到每一个顶点
	{
		x = p[i];
		while (x != -1)
		{
			s.push(x);//将前驱依次压入栈中
			x = p[x];
		}
		cout << "源点到其他各顶点最短路径为;" ;
		while (!s.empty())
		{
			cout << s.top() << "--";//依次取出栈顶元素
			s.pop();//出栈
		}
		cout << i << ";最短距离为:"<< dist[i] << endl;
	}
}



int main()
{
	int u, v, w, st;
	int i;
	system("color 0d");
	cout << "请输入城市的个数:" << endl;
	cin >> n;
	cout << "请输入城市之间的路线个数:" << endl;
	cin >> m;
	cout << "请输入城市之间的路线以及距离:" << endl;
	for ( i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
		{
			map[i][j] = INF;
		}
	while (m--)
	{
		cin >> u >> v >> w;
		map[u][v] = min(map[u][v], w);  //邻接矩阵储存,保留最小的距离
	}
	cout << "请输入小明所在的位置:" << endl;
	cin >> st;
	Dijkstra(st);
	cout << "小明所在的位置:" << st << endl;
	for ( i = 1; i <= n; i++)
	{
		cout << "小明:" << st << "-" << "要去的位置:" << i << endl;
		if (dist[i] == INF)
			cout << "sorry,无路可走" << endl;
		else
			cout << "最短距离为:"<< dist[i]<< endl;
	}

	findpath(st);    //其他输出
	return 0;
}

三、复杂度
(1)时间复杂度为:O(n^2)
(2)空间复杂度为:O(n)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值