算法项目报告:物流中的最短路径问题

问题描述

物流问题

        有一个物流公司需要从起点A到终点B进行货物运输,在运输过程中,该公司需要途径多个不同的城市,并且在每个城市中都有一个配送站点。为了最大程度地降低运输成本和时间,该公司需要确定经过哪些配送站点,并且给出完成货物运输的最短路径长度。

路线分布图

问题分析

问题简化

        可以将该问题抽象为多段图的最短路径问题,其中每个城市对应图中的一个节点,不同城市之间的距离对应着图中的边权,城市内部的配送站可以看作同一个节点。从起点A到终点B的货物运输路径可以表示为多段图中的一条路径。找到起点A到终点B的最短路径并给出路径长度即可求解此问题。

路线简化图

多段图最短路径的填表
下标 1 2 3 4 5 6 7 8 9
元素值 4 8 6 10 8 12 14 17 15
状态转换 0->1 0->2 0->3 1->4 3->5 5->6 5->7 5->8 7->9

最短路径为:0->3->5->7->9,最短路径长度为15

算法设计

算法设计分析

        多段图的最短路径问题满足最优性原理,可以使用动态规划法求解。

        设Cuv表示多段图的有向边<u,v>上的权值,从源点s到终点t的最短路径长度记为d(s,t),原问题的部分解d(s,v),则下式成立:

d(s,v)=Csv                (<s,v>∈E)

d(s,v)=min{d(s,u)+Cuv}     (<u,v>∈E)

数组arc[n][n]存储图的代价矩阵,数组cost[n]存储最短路径长度,cost[j]表示从源点s到顶点j的最短路径长度,数组path[n]记录转移状态,path[j]表示从源点s到顶点j的路径上顶点j的前一个顶点。

算法伪代码

输入:多段图的代价矩阵

输出:最短路径长度及路径c[n][n]

1.循环变量j从1~n-1重复下述操作,执行填表工作

  1.1考察顶点j的所有入边,对于边<i,j>∈E,执行下述操作

     1.1.1cost[j]=min{cost[i]+c[i][j]}

     1.1.2path[j]=使cost[i]+c[i][j]最小的i

  1.2 j++

2.输出最短路径长度cost[n-1]

3.循环变量i=path[n-1],循环直到path[i]=0,输出最短路径经过的顶点

  3.1输出path[i]

  3.2 i=path[i]

实验结果

最短路径

最短路径为:0->3->5->7->9,最短路径长度是15

算法分析

时间复杂度分析

        算法第一部分是依次计算从源点到各个顶点的最短路径长度,由两层循环嵌套组成,外层循环执行n-1次,内层循环对所有入边进行计算,在所有循环中,每条入边只计算一次。假设图的边数为m,时间复杂度为O(m);第二部分是输出最短路径经过的顶点,设多段图划分为k段,时间复杂度为O(k)。整个算法的时间复杂度为O(m+k)。

空间复杂度分析

        算法的空间复杂度主要体现在图的代价矩阵arc[n][n]的存储,空间复杂度为O(n^2),存储最短路径长度的数组cost[n]的空间复杂度为O(n),转移状态记录数组path[n]的空间复杂度为O(n),所以整个算法的空间复杂度为O(n^2)。

源代码

#include<iostream>
using namespace std;
#define INF 999
int arc[10][10]; // 最多10个点 
int CreateGraph()
{
	int i, j, k;
	int weight;
	int vnum, arcnum;
	cout << "请输入顶点和边的个数:";
	cin >> vnum >> arcnum;
	for (int i = 0; i < vnum; i++) 	// 初始化图的代价矩阵 
		for (int j = 0; j < vnum; j++)
			arc[i][j] = INF;

	for (k = 0; k < arcnum; k++)
	{
		cout << "请输入第" << k + 1 << "条边的两个顶点和权值:";
		cin >> i >> j >> weight;
		arc[i][j] = weight;
	}
	return vnum;  // 返回顶点的个数
}
// 求 n个顶点的多段图的最短路径 
int BackPath(int n)
{
	int i, j, temp;
	int cost[100], path[100]; // 存储路径长度和路径 
	for (i = 1; i < n; i++)
	{
		cost[i] = INF;
		path[i] = -1;
	}
	cost[0] = 0;			// 顶点0为源点 
	path[0] = -1;
	for (j = 1; j < n; j++)		// 依次计算后面下标为1到n-1的点(填表) 
		for (i = j - 1; i >= 0; i--)
		{
			if (cost[i] + arc[i][j] < cost[j])
			{
				cost[j] = cost[i] + arc[i][j]; // 更新值 
				path[j] = i;			// 记录前一个点 
			}
		}
	// 输出路径
	i = n - 1;
	cout << "最短路径为:" << i;
	while (path[i] >= 0)// 前一个点大于0 
	{
		cout << "<-" << path[i];
		i = path[i]; // 更新为前一个点 
	}
	cout << endl;
	return cost[n - 1]; // 返回最短路径长度 
}
int main()
{
	int graph = CreateGraph();
	cout << "最短路径长度为:" << BackPath(graph) << endl;
	return 0;
}

感谢大家的观看

相关推荐

  1. 【更新】Leetcode遇到路径算法

    2024-07-17 20:12:04       43 阅读
  2. 使用Dijkstra算法解决路径问题

    2024-07-17 20:12:04       50 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-17 20:12:04       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-17 20:12:04       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-17 20:12:04       58 阅读
  4. Python语言-面向对象

    2024-07-17 20:12:04       69 阅读

热门阅读

  1. 云服务器,nginx访问失败,安全组,0.0.0.0/0

    2024-07-17 20:12:04       21 阅读
  2. 网络安全工作者如何解决网络拥堵

    2024-07-17 20:12:04       21 阅读
  3. docker network(docker网络)介绍

    2024-07-17 20:12:04       23 阅读
  4. 【C语言】条件运算符详解 - 《 A ? B : C 》

    2024-07-17 20:12:04       26 阅读