动态规划求构造最优二叉查找树和最短路径

合集下载

动态规划求最短路径的两种方法

动态规划求最短路径的两种方法

动态规划1.最短路线问题解(1):将上图该画成下图:记a (1,2)=4,a(1,3)=5,依次类推,表示每个点和值的关系。

逆序递推方程:⎪⎩⎪⎨⎧==+++=0)6(61,2,3,4,5)}1(1),({min )(s f k k s k f k u k s k d k uk s k fAB 1B 2C 1 C 2C 3 C 4D 1D 2 D 3E 1 E 2F4523 6 8 7 75845348435 6 2 314 31234 5 6 789 101112134523 6 8 7 7584534 8435 6 2 314 3如图各状态:逆序递推,找出上一个状态到下一阶段的最小路径值。

例如,当K=4时,状态 它们到F 点需经过中途 点E ,需一一分析从E 到 F 的最短路:先说从D1到F 的最短路 有两种选择:经过 E1, E2, 比较最短。

这说明由 D1 到F 的最短距离为7,其路径为AB 1B 2C 1 C 2C 3 C 4D 1 D 2 D 3E 1 E 2F4523 6 87 75845348435 62 31 4 3第1阶段 第2阶段 第3阶段 第4阶段 第5阶段状态 1状态 2状态3状态 4状态 5状态 6)}(),(),(),(m in{)(252141511414E f E D d E f E D d D f ++=.7}35,43min{=++=.11F E D →→},,{3214D D D S =a=[0,4,5,inf,inf,inf,inf,inf,inf,inf,inf,inf,inf 4,0,inf,2,3,6,inf,inf,inf,inf,inf,inf,inf 5,inf,0,inf,8,7,7,inf,inf,inf,inf,inf,inf inf,2,inf,0,inf,inf,inf,5,8,inf,inf,inf,inf inf,3,8,inf,0,inf,inf,4,5,inf,inf,inf,inf inf,6,7,inf,inf,0,inf,inf,3,4,inf,inf,inf inf,inf,7,inf,inf,inf,0,inf,8,4,inf,inf,inf inf,inf,5,4,inf,inf,inf,0,inf,inf,3,5,inf inf,inf,inf,8,5,3,8,inf,0,inf,6,2,inf inf,inf,inf,inf,inf,4,4,inf,inf,0,1,3,inf inf,inf,inf,inf,inf,inf,inf,3,6,1,0,inf,4 inf,inf,inf,inf,inf,inf,inf,5,2,3,inf,0,3 inf,inf,inf,inf,inf,inf,inf,inf,inf,inf,4,3,0]; s8=min(a(8,11)+a(11,13),a(8,12)+a(12,13)); s9=min(a(9,11)+a(11,13),a(9,12)+a(12,13)); s10=min(a(10,11)+a(11,13),a(10,12)+a(12,13)); s4=min(a(4,8)+s8,a(4,9)+s9); s5=min(a(5,8)+s8,a(5,9)+s9); s6=min(a(6,9)+s9,a(6,10)+s10); s7=min(a(7,9)+s9,a(7,10)+s10); s2=[a(2,4)+s4,a(2,5)+s5,a(2,6)+s6]; s2=min(s2);s3=[a(3,5)+s5,a(3,6)+s6,a(3,7)+s7]; s3=min(s3);s1=min(a(1,2)+s2,a(1,3)+s3)运行结果为:s8 = 7 s9 = 5 s10 = 5 s4 = 12 s5 = 10 s6 = 8 s7 = 9 s2 =13s3 = 15 s1 = 17结果分析:s 表示每个点到终点的最短距离,那么最短路程为17。

二维数组最短路径问题

二维数组最短路径问题

二维数组最短路径问题
二维数组最短路径问题可以使用动态规划来解决。

给定一个包含非负整数的m x n网格,要求找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

每次只能向下或者向右移动一步。

思路分析:
1.定义一个dp数组,dp[i][j]表示从左上角到达(i,j)位置的最小路径
和。

2.初始化dp数组的第一行和第一列与网格数组相同。

3.对于其他位置(i,j),从上方位置(i-1,j)和左方位置(i,j-1)到达(i,j)的最
小路径和为上方位置和左方位置的最小路径和与网格数组(i,j)的值之和。

4.最终的答案为dp数组的右下角位置的值。

代码实现:
def minPathSum(grid):
if not grid or not grid[0]:
return 0
m, n = len(grid), len(grid[0])
dp = [[0] * n for _ in range(m)]
dp[0][0] = grid[0][0]
for i in range(1, m):
dp[i][0] = dp[i-1][0] + grid[i][0]
for j in range(1, n):
dp[0][j] = dp[0][j-1] + grid[0][j]
for i in range(1, m):
for j in range(1, n):
dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] return dp[m-1][n-1]
时间复杂度为O(mn),空间复杂度为O(mn)^。

动态规划算法

动态规划算法
3级 28 20 7 2 8 3 f(i, j) —— 从第 i 堆到第 j 堆的代价和。 g(i, j) —— 从第 i 堆到第 j 堆的重量和。 f(1, 3) = 20 + 28 = 48 1级 13 序号 1 = f(1, 2) + g(1, 3)
2级
n=4时:有3大类归并法。前1堆后3堆、前2堆后2堆、前3堆后1堆。
因3堆有2种归并法,所以一共5小类归并法。前1堆第1种情况:
4级 3级 2级 1级 13 序号 1
44 31 15 7
2
f(1, 4) = 15 + 31 + 44 = 90 = f(2, 4) + g(1, 4) w不变 = f(2, 3) + g(2, 4) + g(1, 4)
若f(2,4)越小,则f(1,4)就越小。 8
3
16
4
n=4 时:前1堆的第2种情况。
4级 44 31 24 7 2 8 3 f(1, 4) = 24 + 31 + 44 = 99 = f(2, 4) + g(1, 4) w不变 = f(3, 4) + g(2, 4) + g(1, 4) 若f(2,4)越小,则f(1,4)就越小。 16 4 f(1, 4) = 20 + 24 + 44 = 88
的一种通用方法,对最优化问题提出最优性原则,从而创建最优化问题
的一种新算法设计技术——动态规划,它是一种重要的应用数学工具。 至少在计算机科学圈子里,人们不仅用它解决特定类型的最优化问题, 而最终把它作为一种通用的算法设计技术,即包括某些非最优化问题。 多阶段决策过程最优化: 现实世界里有许多问题属于这种情况:它有很多解,应用要求最优解。 穷举法通过找出全部解,再从中选出最优解。这种方法对于那些计算

《算法设计与分析》第3章 动态规划法

《算法设计与分析》第3章 动态规划法

最优解的递推关系 定义m[i:j],表示矩阵连乘A[i:j]所需的最少计算 量 则有: i j 0 m[i ][ j ] i j minj{m[i ][ k ] m[k 1][ j ] pi 1 pk p j } i k
假设:N个矩阵的维数依序放在一维数组p中, 其中Ai的维数记为Pi-1×Pi
A=A1×A2×A3×…×An
A=(A1×A2×…×Ak) × (Ak+1×Ak+2×…×An)
B
C
1.2 穷举法
穷举法:列举出所有可能的计算次序,并计算出 每一种计算次序相应需要的数乘次数,从中找出 一种数乘次数最少的计算次序。
穷举法复杂度分析: 对于n个矩阵的连乘积,设其不同的计算次序有P(n)种。 由于每种加括号方式都可以分解为两个子连乘的加括号问题: (A1...Ak)(Ak+1…An)可以得到关于P(n)的递推式如下:
【程序】矩阵连乘的 穷举法实现 int MatrixChain::LookupChain(int i, int j) { if(i==j) return 0; int u=LookupChain(i+1,j)+p[i-1]*p[i]*p[j]; //k=i s[i][j]=i; //记录最优分解位置 for ( int k=i+1;k<j; k++ ) { //遍历k int t=LookupChain(i,k)+LookupChain(k+1,j) +p[i]*p[k+1]*p[j+1]; if (t<u) { u=t; s[i][j]=k; //记录最优分解位置 } } int MatrixChain::LookupChain() return u; { } return LookupChain(1,n);

动态规划-最优二叉搜索树

动态规划-最优二叉搜索树

动态规划-最优⼆叉搜索树摘要: 本章介绍了⼆叉查找树的概念及操作。

主要内容包括⼆叉查找树的性质,如何在⼆叉查找树中查找最⼤值、最⼩值和给定的值,如何找出某⼀个元素的前驱和后继,如何在⼆叉查找树中进⾏插⼊和删除操作。

在⼆叉查找树上执⾏这些基本操作的时间与树的⾼度成正⽐,⼀棵随机构造的⼆叉查找树的期望⾼度为O(lgn),从⽽基本动态集合的操作平均时间为θ(lgn)。

1、⼆叉查找树 ⼆叉查找树是按照⼆叉树结构来组织的,因此可以⽤⼆叉链表结构表⽰。

⼆叉查找树中的关键字的存储⽅式满⾜的特征是:设x为⼆叉查找树中的⼀个结点。

如果y是x的左⼦树中的⼀个结点,则key[y]≤key[x]。

如果y是x的右⼦树中的⼀个结点,则key[x]≤key[y]。

根据⼆叉查找树的特征可知,采⽤中根遍历⼀棵⼆叉查找树,可以得到树中关键字有⼩到⼤的序列。

介绍了⼆叉树概念及其遍历。

⼀棵⼆叉树查找及其中根遍历结果如下图所⽰:书中给出了⼀个定理:如果x是⼀棵包含n个结点的⼦树的根,则其中根遍历运⾏时间为θ(n)。

问题:⼆叉查找树性质与最⼩堆之间有什么区别?能否利⽤最⼩堆的性质在O(n)时间内,按序输出含有n个结点的树中的所有关键字?2、查询⼆叉查找树 ⼆叉查找树中最常见的操作是查找树中的某个关键字,除了基本的查询,还⽀持最⼤值、最⼩值、前驱和后继查询操作,书中就每种查询进⾏了详细的讲解。

(1)查找SEARCH 在⼆叉查找树中查找⼀个给定的关键字k的过程与⼆分查找很类似,根据⼆叉查找树在的关键字存放的特征,很容易得出查找过程:⾸先是关键字k与树根的关键字进⾏⽐较,如果k⼤⽐根的关键字⼤,则在根的右⼦树中查找,否则在根的左⼦树中查找,重复此过程,直到找到与遇到空结点为⽌。

例如下图所⽰的查找关键字13的过程:(查找过程每次在左右⼦树中做出选择,减少⼀半的⼯作量)书中给出了查找过程的递归和⾮递归形式的伪代码:1 TREE_SEARCH(x,k)2 if x=NULL or k=key[x]3 then return x4 if(k<key[x])5 then return TREE_SEARCH(left[x],k)6 else7 then return TREE_SEARCH(right[x],k)1 ITERATIVE_TREE_SEARCH(x,k)2 while x!=NULL and k!=key[x]3 do if k<key[x]4 then x=left[x]5 else6 then x=right[x]7 return x(2)查找最⼤关键字和最⼩关键字 根据⼆叉查找树的特征,很容易查找出最⼤和最⼩关键字。

算法设计与分析复习题目及答案 (3)

算法设计与分析复习题目及答案 (3)

分治法1、二分搜索算法是利用(分治策略)实现的算法。

9. 实现循环赛日程表利用的算法是(分治策略)27、Strassen矩阵乘法是利用(分治策略)实现的算法。

34.实现合并排序利用的算法是(分治策略)。

实现大整数的乘法是利用的算法(分治策略)。

17.实现棋盘覆盖算法利用的算法是(分治法)。

29、使用分治法求解不需要满足的条件是(子问题必须是一样的)。

不可以使用分治法求解的是(0/1背包问题)。

动态规划下列不是动态规划算法基本步骤的是(构造最优解)下列是动态规划算法基本要素的是(子问题重叠性质)。

下列算法中通常以自底向上的方式求解最优解的是(动态规划法)备忘录方法是那种算法的变形。

(动态规划法)最长公共子序列算法利用的算法是(动态规划法)。

矩阵连乘问题的算法可由(动态规划算法B)设计实现。

实现最大子段和利用的算法是(动态规划法)。

贪心算法能解决的问题:单源最短路径问题,最小花费生成树问题,背包问题,活动安排问题,不能解决的问题:N皇后问题,0/1背包问题是贪心算法的基本要素的是(贪心选择性质和最优子结构性质)。

回溯法回溯法解旅行售货员问题时的解空间树是(排列树)。

剪枝函数是回溯法中为避免无效搜索采取的策略回溯法的效率不依赖于下列哪些因素(确定解空间的时间)分支限界法最大效益优先是(分支界限法)的一搜索方式。

分支限界法解最大团问题时,活结点表的组织形式是(最大堆)。

分支限界法解旅行售货员问题时,活结点表的组织形式是(最小堆)优先队列式分支限界法选取扩展结点的原则是(结点的优先级)在对问题的解空间树进行搜索的方法中,一个活结点最多有一次机会成为活结点的是( 分支限界法).从活结点表中选择下一个扩展结点的不同方式将导致不同的分支限界法,以下除( 栈式分支限界法)之外都是最常见的方式.(1)队列式(FIFO)分支限界法:按照队列先进先出(FIFO)原则选取下一个节点为扩展节点。

(2)优先队列式分支限界法:按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。

最短路径问题的优化算法

最短路径问题的优化算法

最短路径问题的优化算法最短路径问题是图论中的经典问题之一,涉及在给定图中找到两个节点之间的最短路径。

这个问题在实际生活中有广泛的应用,如导航系统中的路线规划、网络通信中数据包的传输等。

为了提高计算效率,许多优化算法被提出和应用于解决最短路径问题。

1. 单源最短路径问题单源最短路径问题是指在给定图中,从一个固定的起始节点到其他所有节点的最短路径问题。

经典的解决方法包括迪杰斯特拉算法和贝尔曼-福特算法。

迪杰斯特拉算法是一种贪婪算法,通过确定与起始节点距离最短的节点来逐步扩展最短路径树。

具体步骤如下:1) 初始化距离数组,将起始节点距离设为0,其他节点距离设为无穷大。

2) 选择当前距离最短的节点,并标记为已访问。

3) 更新与该节点相邻节点的距离,若经过当前节点到相邻节点的距离更短,则更新距离数组。

4) 重复步骤2和步骤3,直到所有节点都被访问过。

最后,距离数组中记录的即为从起始节点到其他所有节点的最短路径。

贝尔曼-福特算法是一种动态规划算法,通过不断地松弛边来逐步得到最短路径。

具体步骤如下:1) 初始化距离数组,将起始节点距离设为0,其他节点距离设为无穷大。

2) 依次对所有边进行松弛操作,即更新边的端点节点的距离。

3) 重复步骤2,直到所有边都被松弛完毕。

4) 判断是否存在负环路,若存在则说明无最短路径;若不存在,则距离数组中记录的即为从起始节点到其他所有节点的最短路径。

2. 全局最短路径问题全局最短路径问题是指在给定图中,找到任意两个节点之间的最短路径问题。

弗洛伊德算法是一种经典的解决方法,通过动态规划的思想逐步求解。

弗洛伊德算法的具体步骤如下:1) 初始化距离矩阵,将所有节点之间的距离设为无穷大。

2) 根据已知的边信息更新距离矩阵,即将已知路径的距离设为对应的实际距离。

3) 对于每一对节点,考虑经过中转节点的路径是否更短,若更短则更新距离矩阵。

4) 重复步骤3,直到距离矩阵不再变化。

最后,距离矩阵中记录的即为任意两个节点之间的最短路径。

最短路径问题算法

最短路径问题算法

最短路径问题算法最短路径问题算法概述:在图论中,最短路径问题是指在一个加权有向图或无向图中,从一个顶点出发到另外一个顶点的所有路径中,权值和最小的那条路径。

最短路径问题是图论中的经典问题,在实际应用中有着广泛的应用。

本文将介绍常见的几种最短路径算法及其优缺点。

Dijkstra算法:Dijkstra算法是一种贪心算法,用于解决带权有向图或无向图的单源最短路径问题,即给定一个起点s,求出从s到其他所有顶点的最短路径。

Dijkstra算法采用了广度优先搜索策略,并使用了优先队列来维护当前已知的距离最小的节点。

实现步骤:1. 初始化:将起始节点标记为已访问,并将所有其他节点标记为未访问。

2. 将起始节点加入优先队列,并设置其距离为0。

3. 重复以下步骤直至队列为空:a. 取出当前距离起始节点距离最小的节点u。

b. 遍历u的所有邻居v:i. 如果v未被访问过,则将其标记为已访问,并计算v到起始节点的距离,更新v的距离。

ii. 如果v已被访问过,则比较v到起始节点的距离和当前已知的最短距离,如果更小则更新v的距离。

c. 将所有邻居节点加入优先队列中。

优缺点:Dijkstra算法能够求解任意两点之间的最短路径,并且保证在有向图中不会出现负权回路。

但是Dijkstra算法只适用于无负权边的图,因为负权边会导致算法失效。

Bellman-Ford算法:Bellman-Ford算法是一种动态规划算法,用于解决带权有向图或无向图的单源最短路径问题。

与Dijkstra算法不同,Bellman-Ford算法可以处理带有负权边的图。

实现步骤:1. 初始化:将起始节点标记为已访问,并将所有其他节点标记为未访问。

2. 对于每个节点v,初始化其到起始节点s的距离为正无穷大。

3. 将起始节点s到自身的距离设置为0。

4. 重复以下步骤n-1次(n为顶点数):a. 遍历所有边(u, v),如果u到起始节点s的距离加上(u, v)边权小于v到起始节点s的距离,则更新v的距离为u到起始节点s的距离加上(u, v)边权。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

x3
x1
x5
x n-2
xn
……
x n-3
x4
x2
a)原问题
x5
x n-1 x n-2
x3
x1
……
x n-3
x4
x2
b)子问题
x5
x n-1 x n-2
x3
x1Leabharlann ……x n-3x4
x2
c )子问题
图 1 原问题与子问题 b)当 xyk 的横坐标小于 xyk-1 的横坐标,那么就是如下情况 yk=n-2;yk-1=n-1。即为在 图 1 中的 b)情况中,不是由 xn-1 连到点 xn 上,而是由 xn-1 连到 xn-2 上,再有 xn-2 连 到 xn 上。我们同样可以用反证法来证明 x1, xy1, xy2, xy3, …, xyk-1 是子问题 x1, x2, x3, …, xyk-1 的最优解。 (3) 说明子问题的重叠性:就举 4 个点的例子来说明重叠性问题(如图 2 所示)。
xyk, xn 包含子问题 x1, x2, x3, …, xyk 的最优解 x1, xy1, xy2, xy3, …, xyk; b) 若 xyk 的横坐标小于 xyk-1 的横坐标; 则原问题的最优解为子问题 x1, x2, x3, …, xyk-1 的最优解再加上点 xyk 形成,即 x1, xy1, xy2, xy3, …, xyk-1 是子问题 x1, x2, x3, …, xyk-1 的最优解。 证明:a)当 yk=n-1 时,即点 xyk 为点 xn-1,则在最优解中,在 xyk 之前不会有比 xyk 横坐标还要大的点,即最优解包含的前缀 x1, xy1, xy2, xy3, …, xyk 所含有的顶点,全部 在子问题 x1, x2, x3, …, xn-2, xn-1 中,并且该前缀中横坐标最大的点与子问题的最后一 个点是同一个点,所以首先该前缀是子问题 x1, x2, x3, …, xn-2, xn-1 的一个解;再运用 反证法来证明该前缀是该子问题的最优解。如果如果 x1, xy1, xy2, xy3, …, xyk 不是子问 题 x1, x2, x3, …, xyk 的最优解,则一定存在另一个序列 x1, xz1, xz2, xz3, …, xyk 是子问题 x1, x2, x3, …, xyk 的最优解,即其形成的路径最短,那么该最优解再加上 cyk,n 即为问 题 x1, x2, x3, …, xn-1, xn 的一个解,并且其路径要比 x1, xy1, xy2, xy3, …, xyk, xn 要短,这就 与 x1, xy1, xy2, xy3, …, xyk, xn 是最优解相矛盾了,既而得证。同理,在 yk=n-2 时,在 最优解序列中若 xyk 的横坐标大于 xyk-1 的横坐标, 则在最优解的前缀 x1, xy1, xy2, xy3, …, xyk 中 xyk 的横坐标最大,该前缀均来自子问题 x1, x2, x3, …, xn-3, xn-2 中,并且 xyk 即为 xn-2,所以该前缀也是该子问题的一个解,我们同样可以运用反证法来证明该前缀 也是该子问题的一个最优解。xyk 只能取 xn-1、xn-2 这两种情况,因为只有这两点与 点 xn 直接相连。其实该结论说的是由图 1 所示的两种子问题的最后一个点与点 xn 搭一条边形成最终最优解的情况。
11S103001 郝亚峰 2 班 第七次算法作业
1、 根据构造二叉搜索树的最优解的信息来构造优化解。 在求解二叉查找树的最优解的过程中,我们用 Root[i, j]来记录节点序列<i, i+1, …, j>的根节 点,下面,我们就是要通过 Root 数组来构造优化解。我们用(i, j, k)来表示父节点与子节点 关系:i 表示父节点,j 表示左子节点,k 表示右子节点。当某一节点 m 没有子节点时(这里 所说的子节点是指给定节点序列中的某一点),则若没有左子节点,则我们用 dm-1 来时表 示,若没有右子节点,我们用 dm 来表示。算法如下: Print_Optimal_Result(i, j) { if(i<=j) { m=Root[i, j]; print ‘(’; print m; print ‘,’; if(m-1<i) print dm-1; else print Root[i, m-1]; print ‘,’; if(m+1>j) print dm; else print Root[m+1,j]; print ‘)’; Print_Optimal_Result(i, m-1); Print_Optimal_Result(m+1, j); } } 2、 利用动态规划求解最短路径。 问题定义:给定平面上 n 个点,没有任何两点具有相同的 x 坐标值,点按 x 坐标递增排序 为 x1,x2,…,xn。 任何一点只与 x 坐标比它小的和大的最邻近的分别 2 个点有边, 如 x5 与 x3, x4,x6,x7 有边相连,故任何一点最多关联 4 条边(边界点 x1,xn 关联两条边,点 x2, xn-1 关联三条边,其余点关联 4 条边)且如果边为 xixj 时,边的代价为 cij (cij>0)。试用动 态规划方法求出从 x1 到 xn 的代价和最短的一条路径。 解:我们按照这些步骤来解此题:分析最优解的结构—>找问题的优化子结构—>说明子问 题的重叠性—>递归地定义最优解的代价—>递归地划分子问题,直至问题不可再分—>自 底向上的求解子问题(计算优化解的代价并保存、 保存构造最优解的信息)—>根据构造最优 解的信息求解优化解。 (1) 分析最优解的结构:我们用点的序列来表示 x1 到 xn 的最短路径,如下所示: x1, xy1, xy2, xy3, …, xyk, xn 其中,yk∈{n-1, n-2}。 (2) 找问题的优化子结构:如果序列 x1, xy1, xy2, xy3, …, xyk, xn 表示由 x1, x2, x3, …, xn-1, xn 这些点所形成的图中由 x1 到 xn 的最短路径,则有如下结论: a) 若 xyk 的横坐标大于 xyk-1 的横坐标,即最优解序列的倒数第二点的横坐标大于 倒数第三个点的横坐标, 那么问题 x1, x2, x3, …, xn-1, xn 的最优解 x1, xy1, xy2, xy3, …,
0 , if i j d[i, j ] min{d [i, j 1] c j 1, j , d [i, j 2] c j 2, j , d[i, j 1] c j 1, j 2 c j 2, j } , if i j
(5) 递归地分解问题,直到问题不可再分:要求 d[1, n],则需求 d[1, n-1]和 d[1,n-2]; 要求 d[1, n-1], 则需求 d[1, n-2]和 d[1,n-3]; 要求 d[1, n-2]则需求 d[1, n-3]和 d[1, n-4] 等等,一直划分到 d[1, 1]=0。 (6) 自底向上求解:记录最优解和最优解信息,这两项工作我们都由 d[i, j]来完成。算 法如下: a) 求最短路径: Mix_Route() { b[1,1]=0; b[1,2]=b[1,1]+c[1,2];//c[i, j]存放点 xi 与 xj 的边的代价 FOR j=3 TO n DO d[1,j]=min{d[1,j-1]+c[j-1, j], d[1,j-2]+c[j-2, j], d[1,j-1]+c[j-1, j-2]+c[j-2, j]}; return d[1,n]; b) } 求解优化解: Print_Result(int i, int j) { if(j-1>=i&&d[i, j]== d[i,j-1]+c[j-1, j]) { Print_Result(i, j-1); print xj-1; } else if(j-2>=i&&d[i, j]== d[i,j-2]+c[j-2, j]) { Print_Result(i,,j-2); print xj-2; } else if(j-1>=i&&d[i,j]==d[i,j-1]+c[j-1, j-2]+c[j-2, j]) {
x1
x3
x2
x4
图 2 说明子问题重叠性 在图 2 中求 x1 到 x4 的最短路径, 要考虑这么 4 种情况: x1—>x2—>x4; x1—>x3—>x4; x1—>x3—>x2—>x4; x1—>x2—>x3—>x4;我们可以看到第一种情况与第四种情况存在 x1—>x2 的重叠性;第二种情况与第三种情况存在 x1—>x3 的重叠性。 (4) 递归地定义最优解的代价:我们用 d[i, j]来表示由 xi, xi+1, xi+2, …, xj 形成的图中由 xi 到 xj 的最短路径的代价/长度;则根据(2)中的分析得出如下结论:
Print_Result(i,j-1); print xj-1, xj-2; } } 经过以上递归,输出的最优解不包含最后一个点 xn,所以在这个程序之后我 们再加一条语句,输出 xn 即可。 (7) 复杂度分析: a) 空间复杂度:需要二维数组 c[n][n]来存放边的代价,但是每一点最多与其他 的 4 个点有边,所以不需要 O(n2),最多为 4n,所以需要 O(n),我们用 d[i][j] 来记录代价,但是 i 从来就没有改变过,所以其实只需要一个一维数组 d[n] 就可以了,其空间开销也为 O(n);综上,空间复杂度为 O(n)。 b) 时间复杂度: 在求最短路径的程序中, 只有一个循环, 其时间复杂度为 O(n); 在求优化解的程序中,其中有三个递归,但是每次只能执行一个,我们取最 坏的可能,每次执行的都是 Print_Result(i, j-1);而不是 Print_Result(i, j-2);则有 T(n)=T(n-1)+1;其复杂度也为 O(n)。所以时间复杂度为 O(n)。 (8) 题外话:解决本题另外一条思路:逐点扩张(应该是一种贪心)。大体阐述一下这思 路:对于图 1 中的 b)图,我们只要在此图加入点 xn 便形成了原问题,只要求出在 b)图中,x1 到 xn-1 和 xn-2 的最短距离,比较这两个最短距离分别加上相应的边代价 cn-1,n 和 cn-2,n 的大小即可。所以求 d[i,j]只需要求出在 xi, xi+1, …, xj-1 图中的 d[i,j-1]和 d[i,j-2],再分别加上 cn-1,n 和 cn-2,n,比较大小即可。注意,此处的 d[i,j]与上面动态 规划中的含义略有不同, 上面 d[i,j-2]表示 xi, xi+1, …, xj-2 图中由 xi 到 xj-2 的最短距离, 而此处可以表示在 xi, xi+1, …, xj-1 图中由 xi 到 xj-2 的最短距离。但是在图 xi, xi+1, …, xj-1 中加入 xj 后,形成了新图。在这个新图中 d[i,j-1]和 d[i,j-2]需要更新,否则会影响下 一步加入点 xj+1 后计算 d[i,j]的计算。 关键是怎么更新?只需要 d[i,j-1]加上新加入的 两条边之后与 d[i,j-2]比较,如果比 d[i,j-2]小则替换之;同理,d[i,j-2]加上新加入的 两条边之后与 d[i,j-1]比较,如果比 d[i,j-1]小则替换之。所以,我们从起始点每次顺 序加入一个点,通过前两个点计算新加入点的最短路径,在对前两个点的最短路 径进行更新,不断的这样迭代,直到最后一点,这样可求出最短路径。
相关文档
最新文档