动态规划算法举例分析

合集下载

动态规划算法及其在序列比对中应用分析

动态规划算法及其在序列比对中应用分析

动态规划算法及其在序列比对中应用分析序列比对是生物信息学中一个重要的问题,用于比较两个或多个生物序列的相似性和差异性。

在序列比对过程中,动态规划算法是一种常用和有效的方法。

本文将介绍动态规划算法的基本原理和应用,并深入分析其在序列比对中的应用。

1. 动态规划算法基本原理动态规划算法是一种通过把问题分解为相互重叠的子问题,并通过将每个子问题的解存储起来来解决复杂问题的方法。

它通常用于处理具有重叠子问题和最优子结构特性的问题。

动态规划算法的核心思想是将原问题拆解成若干个子问题,通过计算每个子问题的最优解来得到原问题的最优解。

这个过程可以通过建立一个状态转移方程来实现,即找到子问题之间的关联关系。

2. 动态规划在序列比对中的应用序列比对是生物信息学研究中常见的任务之一,用于比较两个或多个生物序列的相似性和差异性。

动态规划算法在序列比对中被广泛应用,最为著名的例子是Smith-Waterman算法和Needleman-Wunsch算法。

2.1 Smith-Waterman算法Smith-Waterman算法是一种用于局部序列比对的动态规划算法。

它通过为每个可能的比对位置定义一个得分矩阵,并计算出从每个比对位置开始的最优比对路径来找到最优的局部比对。

Smith-Waterman算法的基本思路是从比对矩阵的右下角开始,根据得分矩阵中每个位置的得分值和其周围位置的得分值进行计算,并记录下最大得分值及其对应的路径。

最终,通过回溯从最大得分值开始的路径,得到最优的局部比对结果。

2.2 Needleman-Wunsch算法Needleman-Wunsch算法是一种用于全局序列比对的动态规划算法。

它通过为每个比对位置定义一个得分矩阵,并通过计算出从第一个比对位置到最后一个比对位置的最优比对路径来找到最优的全局比对。

Needleman-Wunsch算法的基本思路与Smith-Waterman算法类似,但不同之处在于需要考虑序列的开头和结尾对比对结果的影响。

动态规划的应用举例大全

动态规划的应用举例大全
多背包问题
在0/1背包问题的基础上,通过动态规 划的方式解决多个约束条件下的物品 选择问题。
排程问题
作业车间调度问题
通过动态规划的方式,求解给定一组作业和机器,如何分配作业到机器上,使得 完成时间最早且总等待时间最小。
流水线调度问题
通过动态规划的方式,解决流水线上的工件调度问题,以最小化完成时间和总延 误时间。
应用场景
在基因组测序、进化生物学和生物分类学等领域中,DNA序列比对是关键步骤。通过比对,可以发现物种之间的相 似性和差异,有助于理解生物多样性和进化过程。
优势与限制
动态规划算法在DNA序列比对中具有高效性和准确性,能够处理大规模数据集。然而,对于非常长的序 列,算法可能需要较长时间来运行。
蛋白质结构预测
应用场景
深度学习中的优化算法广泛应用于语音识别、图像处理、 自然语言处理等领域,动态规划可以帮助提高训练效率和 模型的准确性。
自适应控制和系统优化
问题描述
动态规划方法
自适应控制和系统优化是针对动 态系统的优化和控制问题。在这 些问题中,动态规划可以用于求 解最优控制策略和系统参数调整。
通过定义状态转移方程和代价函 数,将自适应控制和系统优化问 题转化为动态规划问题。状态表 示系统的当前状态和参数,代价 函数描述了在不同状态下采取不 同行动的代价。
考虑风险因素和概率
动态规划可以考虑到风险因素和概率,以制定最优的风险评估和管 理策略。
考虑风险承受能力和资本充足率
动态规划可以考虑到风险承受能力和资本充足率,以制定最优的风 险评估和管理策略。
04 动态规划在生物信息学中 的应用
DNA序列比对
算法描述
DNA序列比对是生物信息学中常见的问题,通过动态规划算法可以高效地解决。算法将DNA序列视为字符串,并寻 找两个或多个序列之间的最佳匹配。

动态规划算法及其应用案例解析

动态规划算法及其应用案例解析

动态规划算法及其应用案例解析动态规划算法是计算机科学中一种非常重要的算法,它在许多领域都有大量的应用。

在本文中,我们将介绍动态规划算法的基本思想和特点,并通过一些常见的应用案例来深入理解这个算法。

1. 动态规划算法的基本思想动态规划算法是一种算法设计技术,用于在多阶段决策过程中寻找最优解。

它的基本思想是将一个大问题分解成较小的子问题来解决,然后将这些子问题的解组合起来得到原问题的解。

它与分治算法很类似,但是动态规划算法通常是针对问题的重复性结构进行优化的。

动态规划算法通常适用于满足以下几个条件的问题:(1)问题具有重叠子问题的特点,即一个大问题可以分解为多个子问题,且这些子问题存在相同的子结构;(2)问题具有最优子结构的特点,即一个问题的最优解包含其子问题的最优解。

通过以上两个条件,在通过子问题的最优解推导出大问题的最优解时,我们可以避免重复计算并且保证得到的结果是最优的。

2. 动态规划算法的特点动态规划算法的主要特点包括以下几个方面:(1)动态规划算法使用一个递推公式来计算问题的解,这个递推公式通常是由原问题和子问题之间的关系建立而来的。

(2)动态规划算法使用一个表格来存储子问题的解,这个表格通常称为动态规划表或者状态转移表。

(3)动态规划算法通常需要进行一些预处理操作,例如初始化表格的值,以及确定递推公式的边界条件。

(4)动态规划算法的时间复杂度通常是由子问题的个数和计算每个子问题的时间复杂度来决定的。

3. 应用案例解析下面我们将通过一些常见的应用案例来更好地理解动态规划算法。

(1)背包问题背包问题是指给定一组物品和一个容量为W的背包,选择一些物品放入背包中,使得放入背包的物品的总价值最大。

这个问题可以通过动态规划算法来解决。

我们可以定义一个二维数组f[i][j],表示前i个物品放进容量为j的背包所得到的最大价值。

递推公式可以定义为:f[i][j] = max(f[i-1][j], f[i-1][j-w[i]] + v[i]),其中w[i]表示第i个物品的重量,v[i]表示第i个物品的价值。

动态规划算法的详细原理及使用案例

动态规划算法的详细原理及使用案例

动态规划算法的详细原理及使用案例一、引言动态规划是一种求解最优化问题的算法,它具有广泛的应用领域,如机器学习、图像处理、自然语言处理等。

本文将详细介绍动态规划算法的原理,并提供一些使用案例,以帮助读者理解和应用这一算法的具体过程。

二、动态规划的基本原理动态规划算法通过将问题分解为多个子问题,并利用已解决子问题的解来求解更大规模的问题。

其核心思想是利用存储技术来避免重复计算,从而大大提高计算效率。

具体来说,动态规划算法通常包含以下步骤:1. 定义子问题:将原问题分解为若干个子问题,这些子问题具有相同的结构,但规模更小。

这种分解可以通过递归的方式进行。

2. 定义状态:确定每个子问题的独立变量,即问题的状态。

状态具有明确的定义和可计算的表达式。

3. 确定状态转移方程:根据子问题之间的关系,建立状态之间的转移方程。

这个方程可以是简单的递推关系式、递归方程或其他形式的方程。

4. 解决问题:使用递推或其他方法,根据状态转移方程求解每个子问题,直到获得最终解。

三、动态规划的使用案例1. 背包问题背包问题是动态规划算法的经典案例之一。

假设有一个背包,它能容纳一定重量的物品,每个物品有对应的价值。

目的是在不超过背包总重量的前提下,选取最有价值的物品装入背包。

这个问题可以通过动态规划算法来求解。

具体步骤如下:(1)定义问题:在不超过背包容量的限制下,选取物品使得总价值最大化。

(2)定义状态:令dp[i][j]表示将前i个物品放入容量为j的背包中所能获得的最大价值。

(3)状态转移方程:dp[i][j] = max(dp[i-1][j-w[i]]+v[i], dp[i-1][j]),其中w[i]为第i个物品的重量,v[i]为第i个物品的价值。

(4)解决问题:根据状态转移方程依次计算每个子问题的解,并记录最优解,直到获得最终答案。

2. 最长公共子序列最长公共子序列(Longest Common Subsequence,简称LCS)是一种经典的动态规划问题,它用于确定两个字符串中最长的共同子序列。

动态规划算法详解及经典例题

动态规划算法详解及经典例题

动态规划算法详解及经典例题⼀、基本概念(1)⼀种使⽤多阶段决策过程最优的通⽤⽅法。

(2)动态规划过程是:每次决策依赖于当前状态,⼜随即引起状态的转移。

⼀个决策序列就是在变化的状态中产⽣出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。

假设问题是由交叠的⼦问题所构成,我们就能够⽤动态规划技术来解决它。

⼀般来说,这种⼦问题出⾃对给定问题求解的递推关系中,这个递推关系包括了同样问题的更⼩⼦问题的解。

动态规划法建议,与其对交叠⼦问题⼀次重新的求解,不如把每⼀个较⼩⼦问题仅仅求解⼀次并把结果记录在表中(动态规划也是空间换时间的)。

这样就能够从表中得到原始问题的解。

(3)动态规划经常常使⽤于解决最优化问题,这些问题多表现为多阶段决策。

关于多阶段决策:在实际中,⼈们经常遇到这样⼀类决策问题,即因为过程的特殊性,能够将决策的全过程根据时间或空间划分若⼲个联系的阶段。

⽽在各阶段中。

⼈们都须要作出⽅案的选择。

我们称之为决策。

⽽且当⼀个阶段的决策之后,经常影响到下⼀个阶段的决策,从⽽影响整个过程的活动。

这样,各个阶段所确定的决策就构成⼀个决策序列,常称之为策略。

因为各个阶段可供选择的决策往往不⽌⼀个。

因⽽就可能有很多决策以供选择,这些可供选择的策略构成⼀个集合,我们称之为同意策略集合(简称策略集合)。

每⼀个策略都对应地确定⼀种活动的效果。

我们假定这个效果能够⽤数量来衡量。

因为不同的策略经常导致不同的效果,因此,怎样在同意策略集合中选择⼀个策略,使其在预定的标准下达到最好的效果。

经常是⼈们所关⼼的问题。

我们称这种策略为最优策略,这类问题就称为多阶段决策问题。

(4)多阶段决策问题举例:机器负荷分配问题某种机器能够在⾼低两种不同的负荷下进⾏⽣产。

在⾼负荷下⽣产时。

产品的年产量g和投⼊⽣产的机器数量x的关系为g=g(x),这时的年完善率为a,即假设年初完善机器数为x,到年终时完善的机器数为a*x(0<a<1);在低负荷下⽣产时,产品的年产量h和投⼊⽣产的机器数量y 的关系为h=h(y)。

动态规划例题

动态规划例题

动态规划例题动态规划是一种以最优化原理为基础的问题求解方法,通过拆分问题为若干阶段,每个阶段求解一个子问题,再逐步推导出整个问题的最优解。

例如,有一个背包能够承受一定的重量,现有一些物品,每个物品都有自己的重量和价值。

我们希望将物品放入背包中,使得背包的总价值最大。

这个问题可以用动态规划来解决。

首先,我们定义一个二维数组dp,其中dp[i][j]表示在前i个物品中,容量为j的背包中所能放入的物品的最大价值。

那么,对于每一个物品,可以选择放入背包或者不放入背包。

如果选择放入背包,最大价值为dp[i-1][j-w[i]] + v[i],其中w[i]表示第i个物品的重量,v[i]表示第i个物品的价值。

如果选择不放入背包,最大价值为dp[i-1][j]。

因此,dp[i][j]的状态转移方程为:dp[i][j] = max(dp[i-1][j-w[i]] + v[i], dp[i-1][j])。

基于这个状态转移方程,可以逐步求解从第1个物品到第n个物品的最大价值。

最终,dp[n][W]即为问题的最优解,其中W 表示背包的容量。

举个简单的例子,假设背包的容量为10,有3个物品,它们的重量分别为3、4、5,价值分别为4、5、6。

此时,可以得到如下的dp矩阵:0 0 0 0 0 0 0 0 0 0 00 0 0 4 4 4 4 4 4 4 40 0 0 4 5 5 9 9 9 9 90 0 0 4 5 5 9 10 10 14 14我们可以看到,dp[3][10]的最大价值为14,表示在前3个物品中,容量为10的背包中所能放入的物品的最大价值为14。

通过动态规划,我们可以有效地求解背包问题,得到物品放入背包的最优解。

这个例子只是动态规划的一个简单应用,实际上,动态规划可以解决各种复杂的问题,如最长公共子序列、最大子数组和、最大字段和等。

因此,学习动态规划是非常有意义的。

动态规划算法(一)

动态规划算法(一)
}
动态规划:向后处理(K段图)Байду номын сангаас
BC ( i,j) O m S B iT n C ( i 1 ,O l) c ( l,S j) T l V i 1 l,j E
动态规划:0/1背包问题
对于0/1背包问题,可以通过作出变量x1,x2,…,xi的一个 决策序列来得到它的解。而对变量x的决策就是决定它 们是取0还是取1值。
动态规划:0/1背包-向后处理
先求解f0: i> 当x≥0,f0(x)=0 ii> 当x<0, f0(x)=-∞
利用递推式,求出f1, f2, …, fn
动态规划:0/1背包求解实例
考虑如下背包问题: n=3 (w1, w2, w3)=(2, 3, 4) (p1, p2, p3)=(1,2,5) M=6
求解过程(图解法求解):
i=3: f2(x-w3)+p3
8 7 6 5 4 3 2 1
12
567
9
f3(x)
8 7 6 5 4 3 2 1
1234
67
9
动态规划:0/1背包-向后处理
i=1: f0(x-w1)+p1
f1(x)
2 1
2
6
i=2: f1(x-w2)+p2
3 2 1
2
56
2 1
2
6
f2(x)
C( O i,j) S m T c (ij,l n ) CO (i 1 ,l) ST l V i 1 j,lE
动态规划:向前处理算法
void function FGRAPH(E, int k, int n, int P[]){ int COST[n]; int D[n-1]; int r, j; COST[n]=0; for(j=n-1; j<=1; j--){ r是这样的节点,<j,r>∈E且使c(j,r)+COST[r]最小 COST[j]=c(j,r)+COST[r]; D[j]=r; } P[1]=1; P[k]=n; for(j=2;j<=k-1;j++){ P[j]=D[P(j-1)]; }

动态规划算法的常见实例

动态规划算法的常见实例

动态规划算法的常见实例动态规划算法是一种将复杂问题分解为简单子问题来解决的算法,它可被应用于多个领域中,如经济学、生物学、计算机科学等。

在本文中,我们将详细讨论动态规划算法的常见实例。

一、最长公共子序列问题最长公共子序列(LCS)问题是一个经典的计算机科学问题,它要求在两个字符串中找到最长的相同连续子序列。

例如,对于字符串“ABCD”和“ACDF”,最长公共子序列为“ACD”。

使用动态规划方法来解决LCS问题。

首先定义一个m行n列的二维矩阵,其中m和n分别表示两个字符串的长度。

然后,使用以下递推关系:1. 如果一个字符串的长度为0,LCS为0。

2. 如果两个字符不相同,则LCS为它们的前一个字符集合和它们的后一个字符集合的最大值。

3. 如果两个字符相同,则LCS为它们的前一个字符集合和它们的后一个字符集合所组成的子序列中的最大值加1。

最后,矩阵右下角的值就是LCS的长度。

二、背包问题背包问题(Knapsack problem)是一个经典的组合优化问题,被广泛应用于计算机科学和其他领域。

在一个决策者必须决定是否将某些物品放入背包中的场景中,背包问题就发挥了作用。

具体来说,我们要解决的问题是:对于一个固定容量的背包,有一些物品,它们的重量和价值都不同,如何在不超过背包容量的前提下,使所装载物品的总价值最大化。

一种解决方案是使用动态规划方法。

定义一个二维数组,其行表示物品,列表示背包大小。

然后,使用以下递推关系:1. 如果所考虑的物品重量大于背包容量,则不选此物品。

2. 否则,在选取该物品和不选该物品两种情况中选择最优解作为最终结果。

最后,矩阵中右下角的值就是最大的总价值。

三、矩阵链乘法矩阵链乘法是一种计算矩阵乘积的优化算法。

它使用动态规划算法来确定矩阵乘积的最小值。

对于一个长度为n的矩阵链,我们可以定义一个n×n 的矩阵M,其中第i行第j列的元素Mi,j表示第i个矩阵与第j个矩阵相乘的最小次数。

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

动态规划算法1. 动态规划算法介绍基本思想是将待求解问题分解成若干子问题,先求解子问题,最后用这些子问题带到原问题,与分治算法的不同是,经分解得到的子问题往往是不是相互独立,若用分治则子问题太多。

2. 适用动态规划算法问题的特征(1)最优子结构设计动态规划算法的第一步骤通常是要刻画最优解的结构。

当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。

问题的最优子结构性质提供了该问题可用动态规划算法求解的重要线索。

在动态规划算法中,问题的最优子结构性质使我们能够以自底向下的方式递归地从子问题的最优解逐步构造出整个问题的最优解。

同时,它也使我们能在相对小的子问题空间中考虑问题。

(2)重叠子问题可用动态规划算法求解的问题应具备的另一基本要素是子问题的重叠性质。

在用递归算法自顶向下解此问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。

动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,当再次需要解此子问题时,只有简单地用常数时间查看一下结果。

通常,不同的子问题个数随输入问题的大小呈多项式增长。

因此,用动态规划算法通常只需要多项式时间,从而获得较高的解题效率。

(3)备忘录方法动态规划算法的一个变形是备忘录方法。

备忘录方法也是一个表格来保存已解决的子问题的答案,在下次需要解此子问题时,只要简单地查看该子问题的解答,而不必重新计算。

与动态规划算法不同的是,备忘录方法的递归方式是自顶向下的,而动态规划算法则是自底向上递归的。

因此,备忘录方法的控制结构与直接递归方法的控制结构相同,区别在于备忘录方法为每个解过的子问题建立了备忘录以备需要时查看,避免了相同子问题的重复求解。

备忘录方法为每个子问题建立一个记录项,初始化时,该记录项存入一个特殊的值,表示该子问题尚未求解。

在求解过程中,对每个待求的子问题,首先查看其相应的记录项。

若记录项中存储的是初始化时存入的特殊值,则表示该子问题是第一次遇到,则此时计算出该子问题的解,并保存在其相应的记录项中。

若记录项中存储的已不是初始化时存入的特殊值,则表示该子问题已被计算过,其相应的记录项中存储的是该子问题的解答。

此时,只要从记录项中取出该子问题的解答即可。

3. 基本步骤a 、找出最优解的性质,并刻画其结构特征。

b 、递归地定义最优值。

c 、以自底向上的方式计算出最优值。

d 、根据计算最优值时得到的信息构造一个最优解。

(可省) 例1-1 [0/1背包问题] [问题描述]用贪心算法不能保证求出最优解。

在0/1背包问题中,需要对容量为c 的背包进行装载。

从n 个物品中选取装入背包的物品,每件物品i 的重量为iw ,价值为iv 。

对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高,即∑=ni iix v1取得最大值。

约束条件为cx wni i i≤∑=1,{}()n i x i ≤≤∈11,0。

在这个表达式中,需要求i x的值。

i x=1表示物品i装入背包中,i x=0表示物品i不装入背包。

1.找出最优解性质考察上述0 / 1背包问题。

如前所述,在该问题中需要决定x1,…,xn的值。

假设按i = 1,2,…,n 的次序来确定xi 的值。

如果置x1 = 0,则问题转变为相对于其余物品(即物品2,3,…,n),背包容量仍为c 的背包问题。

若置x1 = 1,问题就变为关于最大背包容量为c-w1 的问题。

现设r∈{c,c-w1 } 为剩余的背包容量。

在第一次决策之后,剩下的问题便是考虑背包容量为r 时的决策。

不管x1 是0或是1,[x2 ,…,xn ] 必须是第一次决策之后的一个最优方案,如果不是,则会有一个更好的方案[y2,…,yn ],因而[x1,y2,…,yn ]是一个更好的方案。

因此最优解符合条件,cxwywxwniiiniii≤+≤∑∑==2111。

例:假设n=3, w=[100,14,10], p=[20,18,15], c= 116。

若设x1 = 1,则在本次决策之后,可用的背包容量为r= 116-100=16 。

[x2,x3 ]=[0,1] 符合容量限制的条件,所得值为1 5,但因为[x2,x3 ]= [1,0] 同样符合容量条件且所得值为1 8,因此[x2,x3 ] = [ 0,1] 并非最优策略。

即x= [ 1,0,1] 可改进为x= [ 1,1,0 ]。

若设x1 = 0,则对于剩下的两种物品而言,容量限制条件为11 6。

总之,如果子问题的结果[x2,x3 ]不是剩余情况下的一个最优解,则[x1,x2,x3 ]也不会是总体的最优解。

2.递归定义最优解在上述例题的0 / 1背包问题中,最优决策序列由最优决策子序列组成。

假设m(i,v) 表示例子中剩余容量为j,剩余物品为i,i+1,…,n 时的最优解的值,即:nn nw j w j v j n m ≤≤≥⎩⎨⎧=00),( (1)和{}ii i i w j w j j i m v w j i m j i m j i m ≤≥⎩⎨⎧++-++=0),1(),1(),,1(max ),((2)因此,m (1,c )是初始时最优问题的最优解。

现在计算xi 值,步骤如下:若m(1 ,c) =m( 2 ,c),则x1 = 0,否则x1 = 1。

接下来需从剩余容量c-w1中寻求最优解,用m(2, c-w1) 表示最优解。

依此类推,可得到所有的xi (i= 1,2,…,n) 值。

[0/1背包问题的C 语言实现算法]#define N 12void Knapsack(int v[],int w[],int c,int n,int m[6][N]) {int i,j,jMax,k;jMax=(w[n]-1<c?w[n]-1:c); for(i=0;i<=jMax;i++) m[n][i]=0;for(i=w[n];i<=c;i++) m[n][i]=v[n];for(i=n-1;i>1;i--){jMax=(w[i]-1<c?w[i]-1:c); for(j=0;j<=jMax;j++) m[i][j]=m[i+1][j]; for(j=w[i];j<=c;j++){k=j-w[i];if(m[i+1][j]<m[i+1][k]+v[i]) m[i][j]=m[i+1][k]+v[i]; elsem[i][j]=m[i+1][j]; } }m[1][c]=m[2][c]; if(c>=w[1]) {k=c-w[1];m[1][c]=(m[2][c]>m[2][k]+v[1])?m[2][c]:m[2][k]+v[1]; }}void Traceback(int m[6][N],int w[],int c,int n,int x[]){int i;for(i=1;i<N;i++){if(m[i][c]==m[i+1][c])x[i]=0;else{x[i]=1;c-=w[i];}}x[n]=(m[n][c])?1:0;}main(){int i,c=10,n=5,w[]={0,2,2,6,5,4},v[]={0,6,3,5,4,6}; int m[6][N]={0};int x[6]={0};int j;Knapsack(v,w,c,n,m);for(i=1;i<=n;i++){for(j=1;j<=c;j++)printf("%3d",m[i][j]);printf("\n");}Traceback(m,w,c,n,x);for(i=1;i<=n;i++){if(x[i])printf("%4d:%4d",i,v[i]);}printf("\n");}例2-1 [最短路径问题][问题描述]现有一张地图,各结点代表城市,两结点间连线代表道路,线上数字表示城市间的距离。

如图2所示,试找出从结点1到结点7的最短路径。

① ② ⑤③ ④ ⑦⑥图2 有向图1. 找出最优解性质在第一次决策到达了某个节点i v之后,不管iv 怎样确定,剩下的问题就是选择从iv 到jv 的最短路径。

在所有点对最短路径问题( a l l - p a i r sshorest-paths problem )中,要寻找有向图G 中每对顶点之间的最短路径。

也就是说,对于每对顶点(i, j),需要寻找从i 到j 的最短路径及从j 到i 的最短路径。

因此对于一个n 个顶点的图来说,需寻找p =n(n-1) 条最短路径。

假定图G 中不含有长度为负数的环路,只有在这种假设下才可保证G 中每对顶点(i, j) 之间总有一条不含环路的最短路径。

2. 递归定义最优值上述问题已经转化为寻找从i 到j 的最短路径。

若记最短路径的长度为ee[j].逊县将其初始值赋值为 。

设k 为从i 到j 中节点编号中最大的数,则用C (i ,j ,k )表示经过节点k 的<i ,j>通路的路径长度。

若C (i ,j ,k )< ee[j],则ee[j] =C (i ,j ,k )。

69 9454 5865 78如此寻遍<i,j>中每条通路,则得到的ee[j]为<i,j>的最短路径长度。

最后递归得到从节点1到节点7的最短路径长度。

[最短路径问题的C语言算法实现]#include <stdio.h>#define N 7 /* 顶点数目 */ #define I 999 /* 表示无穷大 */int graph[N][N] = { /* 图的邻接矩阵 */ {I, 4, 5, 8, I, I, I},{I, I, I, 6,6, I, I},{I, I, I, 5, I, 7, I},{I, I, I, I, 8, 9, 9},{I, I, I, I, I, I, 5},{I, I, I, I, I, I, 4},{I, I, I, I, I, I, I}};int List[N]; /* 存放拓扑序列 */ int TopologicalOrder(); /* 拓扑排序函数 */void main() /* 主函数 */ { int i, j, k, l;int ee[N]; /* 最短距离 */int path_e[N][N], n_e[N]; /* 记录路径数据 *//* 初始化数据 */for (i = 0; i < N; i++) {n_e[i] = 0; /* 到 i 的最短路线的结点数 */ee[i] = I; }ee[0] = 0; /* 初始化头结点 */path_e[0][0] = 0;n_e[0] = 1;/* 拓扑排序 */if (!TopologicalOrder())return;/* 对于拓扑序列,运用动态规划步步算出最短路线 */for (i = 0; i < N; i++) {k = List[i]; /* 提取拓扑序列的元素 */ for (j = 0; j < N; j++) /* 更新它所指向顶点的所有数据 */{ if (graph[k][j] != I) /* 寻找指向的顶点 */if (graph[k][j] + ee[k] < ee[j]) /* 如果新路径更短 */{ee[j] = graph[k][j] + ee[k]; /* 更新最短路径长度 */ for (l = 0; l < n_e[k]; l++) /* 更新最短路线 */ { path_e[j][l] = path_e[k][l];}path_e[j][l] = j;n_e[j] = l + 1;}}}}/* 输出结果到屏幕 */for (i = 0; i < N; i++) {printf("shortest(%d): %2d Path: ", i + 1, ee[i]);for (j = 0; j < n_e[i]; j++) {printf("%d ", path_e[i][j] + 1);}printf("\n");}}int TopologicalOrder(){int i, j, top, count;int indegree[N], Stack[N];top = 0; /* 栈顶标志 */for (i = 0; i < N; i++) {indegree[i] = 0; /* 初始化入度 */for (j = 0; j < N; j++) {if (graph[j][i] != I) { /* 如连通 */indegree[i]++; /* 入度自增1 */}}if (!indegree[i]){ /* 如入度为零 */Stack[top++] = i; /* 入栈 */ }}count = 0;while (top != 0) /* 输出顶点数 */{ i = Stack[--top];List[count++] = i;for (j = 0; j < N; j++) {if (graph[i][j] != I) { /* 如连通 */if (!(--indegree[j])) { /* 而且入度为零 */Stack[top++] = j; /* 入栈 */}}}/* for */}/* while */return (count < N) ? 0 : 1;}例3 [航费问题]某航线价格表为:从亚特兰大到纽约或芝加哥,或从洛杉矶到亚特兰大的费用为$ 100;从芝加哥到纽约票价$20;而对于路经亚特兰大的旅客,从亚特兰大到芝加哥的费用仅为$20。

相关文档
最新文档