算法学习-最短路径条数问题(队列相关)

题目

给定如图所示的无向连通图,嘉定图中所有边的权值都为1,显然,从原点A到终点T的最短路径有多条,求不同的最短路径的数目。


分析

权值相同的最短路径问题,则单元点Dijkstra算法退化成BFS广度优先搜索,假定起点为0,终点为N:

结点步数step[0...N-1]初始化为0,记录从A到其他结点的最短路径的步数

路径数目pathNum[0...N-1]初始化为0,记录从A到其他结点的最短路径的条数

pathNum[0]=1,从A到A有1条


若从当前结点i扩展到邻接结点j时有以下两种情况

1、step[j] == 0,这种情况意味着还有有任何路径到达j所以此时到达j的最短路径为到达i的最短路径加1,到达j的最短路径的条数即为到达i的最短路径的条数

即step[j] = step[i] + 1; pathNum[j] = pathNum[i];

2、step[j] == step[i] + 1,则说明出了通过i以外已经有别的路径到达了j,而且所用步数和这个相同,所以这时候这时候到达j的最短路径为到达i的最短路径就不需要变化,到达j的最短路径的条数等于原来的条数在加上到达i的最短路径的条数

即pathNum[j] += pathNum[i]; 


代码如下

// suanfa1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <stdlib.h>
#include <queue>

const int N = 16;

int Calc(int G[N][N])
{
	int step[N];    // 每个结点第几步可以到达
	int stepNumber[N];   // 每个结点有几种走法
	memset(step, 0, sizeof(int) * N);
	memset(stepNumber, 0, sizeof(int) * N);
	stepNumber[0] = 1;
	std::queue<int> q;   // 当前搜索结点
	q.push(0);
	int from, i, s;
	while (!q.empty())
	{
		from = q.front();
		q.pop();
		s = step[from] + 1;
		for (i = 1; i < N; i++)         // 0是起点,不遍历
		{
			if (G[from][i] == 1)      // 连通
			{
				// i尚未可达或发现更快的路(权值不同才可能)
				if ((step[i] == 0) || (step[i] > s))
				{
					step[i] = s;
					stepNumber[i] = stepNumber[from];
					q.push(i);
				}
				else if (step[i] == s)  // 发现相同长度的路径
				{
					stepNumber[i] += stepNumber[from];
				}
			}
		}
	}

	return stepNumber[N - 1];
}

int _tmain(int argc, _TCHAR* argv[])
{
	int G[N][N];
	memset(G, 0, sizeof(int) * N * N);
	G[0][1] = G[0][4] = 1;
	G[1][5] = G[1][0] = G[1][2] = 1;
	G[2][1] = G[2][6] = G[2][3] = 1;
	G[3][2] = G[3][7] = 1;
	G[4][0] = G[4][5] = 1;
	G[5][1] = G[5][4] = G[5][6] = G[5][9] = 1;
	G[6][2] = G[6][5] = G[6][7] = G[6][10] = 1;
	G[7][3] = G[7][6] = 1;
	G[8][9] = G[8][12] = 1;
	G[9][8] = G[9][13] = G[9][10] = 1;
	G[10][9] = G[10][14] = G[10][11] = 1;
	G[11][10] = G[11][15] = 1;
	G[12][8] = G[12][13] = 1;
	G[13][9] = G[13][12] = G[13][14] = 1;
	G[14][10] = G[14][13] = G[14][15] = 1;
	G[15][11] = G[15][14] = 1;

	std::cout<<Calc(G)<<std::endl;
	system("pause");
	return 0;
}

详细介绍一下改程序的执行过程

用队列来记录将要作为当前的结点,如果结点处理过,则弹出队列,这保证了他是广度搜索,处理每一个结点的时候会遍历图中所有结点,除0外,然后根据上面介绍过的方法更新数组,这样保证已经遍历过的结点是正确的,那么在正确的结点基础上去推理其他结点,也应该是正确的,其实我感觉这个也是动态规划的思想



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值