第八讲 动态规划与最短路径(2)_727104450
动态规划求最短路径的两种方法

动态规划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。
运用动态规划模型解决最短路径问题

运用动态规划模型解决物流配送中的最短路径问题王嘉俊(盐城师范学院数学科学学院09(1)班)摘要:随着现代社会的高速发展,物流配送成为了连接各个生产基地的枢纽,运输的成本问题也成为了企业发展的关键。
运费不但与运量有关,而且与运输行走的线路相关。
传统的运输问题没有考虑交通网络,在已知运价的条件下仅求出最优调运方案,没有求出最优行走路径。
文中提出“网络上的物流配送问题“,在未知运价,运量确定的情况下,将运输过程在每阶段中选取最优策略,最后找到整个过程的总体最优目标,节省企业开支。
关键词:动态规划,数学模型,物流配送,最优路径1 引言物流配送是现代化物流系统的一个重要环节。
它是指按用户的订货要求, 在配送中心进行分货、配货, 并将配好的货物及时送交收货人的活动。
在物流配送业务中, 合理选择配送径路, 对加快配送速度、提高服务质量、降低配送成本及增加经济效益都有较大影响。
物流配送最短径路是指物品由供给地向需求地的移动过程中, 所经过的距离最短(或运输的时间最少, 或运输费用最低) , 因此, 选定最短径路是提高物品时空价值的重要环节。
[1]经典的Dijkstra 算法和Floyd 算法思路清楚,方法简便,但随着配送点数的增加,计算的复杂性以配送点数的平方增加,并具有一定的主观性。
我国学者用模糊偏好解试图改善经典方法[]5,取得了较好的效果。
遗憾的是,模糊偏好解本身就不完全是客观的。
文献[]6详细分析了经典方法的利弊之后,提出将邻接矩阵上三角和下三角复制从而使每条边成为双通路径,既适用于有向图也适用于无向图, 但复杂性增加了。
为了避免上述方法存在的不足,本文以动态规划为理论,选择合理的最优值函数,用于解决物流配送最短路径问题。
动态规划是解决多阶段决策过程最优化问题的一种数学方法。
1951年美国数学家Bellman(贝尔曼)等人根据一类多阶段决策问题的特性,提出了解决这类问题的“最优性原理”,并研究了许多实际问题,从而创建了最优化问题的一种新方法——动态规划。
动态规划------最短路径问题

动态规划------最短路径问题最短路径问题是动态规划的⼀个实例。
1.最短路径问题的描述2.举个例⼦来说明:求从 S 到 T 的最短路径。
3.思考⽅式4.利⽤动态规划求解问题依次考虑从 C 到 T 的最短距离。
考虑从 B 到 C 的最短距离考虑从 A 到 B 的最短距离考虑从 T 到 A 的最短距离每次都是最短距离。
在整个过程中,我们把我们的⽬标问题转化成了⼀个个的⼦问题,在⼦问题求最⼩值,最后解决了这个问题。
4.⼦问题的界定5.最短路程之间的依赖关系每⼀次计算的时候都是依据前⼀个⼦问题。
不需要⼀个⼀个计算。
每次计算都可以直接利⽤前⼀个问题的解。
6.⼦问题的优化原则6.利⽤动态规划求解是需要条件的,⼀个反例告诉你,动态规划求解的条件分析:假如从S 到 T 经过的节点依次是 A B C ,从C 到 T ,模10,我们选择上⾯的2 . 从 B 到 C,我们的两条路分别是 4 和 7 ,模10,我们选择上⾯的 4 ,那么,从B到T的最短距离就是 6;从 A 到 B ,我们的两条路分别是 6 和 9,模10,我们选择上⾯的路。
从 S 到 A ,两条路分别是 8 和 11,此时,模10,我们选择下⾯的路。
这时,路径就如上图中蓝⾊的路径了。
但是,这是最优的路径吗?显然不是,红⾊的路线才是最优的路径。
因为模10后,得到的结果为0,⽐ 1 ⼩。
为什么是错误的?因为破坏了动态规划的优化原则,它的问题和它的⼦问题的优化函数之间没有依赖关系。
⽐如,我们考虑最后⼀段即 C 到 T的距离,显然, 2是最优解,⽽不是 5 。
因此,破坏了优化原则的问题不能使⽤动态规划。
7.动态规划⼩结可以⽤于求解组合优化问题。
注意动态规划的最优化的原则。
8.代码这个问题的简化版本,编码实现:从矩阵的(0,0)位置到矩阵的(array.length-1,array[0].length-1)的位置的最⼩值。
动态规划实现最短路径问题

动态规划实现最短路径问题⼀、设计最短路径的动态规划算法 <算法导论>中⼀般将设计动态规划算法归纳为下⾯⼏个步骤: 1)分析最优解的结构 2)递归定义最优解的值 3)⾃底向上计算最优解的值 4)从计算的最优解的值上⾯构建出最优解⼆、最短路径的结构 从最优解的结构开始分析(我们假设没有权值为负的路径),对于图G<V,E>的所有结点对最短路径的问题,我们能知道⼀条最短路径的⼦路径都是最短路径。
假设⽤邻接矩阵W=w(ij)来表⽰输⼊带权图,考虑从结点i到结点j的⼀条最短路径p,如果p最多有m(m为有限值)条边。
若i=j,则p的权值为0⽽且不包含其他边。
若i ≠ j,可以将i到j的路径转换为i -> k、k->j。
三、⼀个给定的图 1)给定⼀个有向图 2)我们可以给出这个有向图的邻接矩阵四、C++实现1 #include <iostream>2 #include<fstream>3 #include<sstream>4 #include<vector>5 #include<string>6using namespace std;7const int Max_Num = 100;89 typedef struct Point {10int n; //点的个数11double p[Max_Num];12double q[Max_Num];13int root[Max_Num][Max_Num];14double w[Max_Num][Max_Num];15double e[Max_Num][Max_Num];16 }Point;1718 vector<Point> points;19 vector<string> res;20 vector<int> num;2122void file_read();23void createPoint();24void optimalBST();25void printRoot(Point P);26void printOptimalBST(int i, int j, int r, Point P, ofstream &fileWrite);27 template <class Type>28 Type stringToNum(const string& str) {29 istringstream iss(str);30 Type num;31 iss >> num;32 iss.str("");33return num;34 }3536void file_read() {37string str2, str1 = "", result;38 ifstream fileRead("in.dat");39if (fileRead.is_open()) {40while (getline(fileRead, str2, '\n')) {41if (str2.find("") != -1) {42 str1.append(str2 + "");43 }44else {45 num.push_back(stringToNum<int>(str2));46if (str1 != "") {47 res.push_back(str1);48 }49 str1 = "";50 }51 }52 res.push_back(str1);53 fileRead.close();54 }55 }5657void createPoint() {58string temp;59 Point P;60for (int i = 0; i < res.size(); i++) {61 vector<string> temp_str; //存放按照空格分开后的数字62int n = num[i];63 stringstream input(res[i]);64while (input >> temp) {65 temp_str.push_back(temp);66 }67 P.n = n;68for(int k = 0; k<=n; k++) P.p[k] = stringToNum<double>(temp_str[k]);69for(int k = n + 1; k<temp_str.size(); k++) P.q[k-(n+1)] = stringToNum<double>(temp_str[k]);70 points.push_back(P);71 }72 }7374//根据书上的伪代码:接收概率列表p1....pn和q0.....qn以及规模n作为输⼊计算出e和root75void optimalBST(){76 Point P;77for(int i = 0; i<res.size(); i++) {78 vector<string> temp_str; //存放按照空格分开后的数字79int n = num[i];80string temp;81 stringstream input(res[i]);82while (input >> temp) {83 temp_str.push_back(temp);84 }85 P.n = n;8687for(int k = 0; k<=n; k++) P.p[k] = stringToNum<double>(temp_str[k]);88for(int k = n + 1; k<temp_str.size(); k++) P.q[k-(n+1)] = stringToNum<double>(temp_str[k]); 8990//初始化只包括虚拟键的⼦树91for (int i = 1;i <= P.n + 1;++i){92 P.w[i][i-1] = P.q[i-1];93 P.e[i][i-1] = P.q[i-1];94 }95//由下到上,由左到右逐步计算96for (int len = 1;len <= P.n;++len){97for (int i = 1;i <= P.n - len + 1;++i){98int j = i + len - 1;99 P.e[i][j] = Max_Num;100 P.w[i][j] = P.w[i][j-1] + P.p[j] + P.q[j];101//求取最⼩代价的⼦树的根102for (int r = i;r <= j;++r)103 {104double temp = P.e[i][r-1] + P.e[r+1][j] + P.w[i][j];105if (temp < P.e[i][j])106 {107 P.e[i][j] = temp;108 P.root[i][j] = r;109 }110 }111 }112 }113 points.push_back(P);114 }115 }116117void printOptimalBST(int i, int j, int r, Point P, ofstream &fileWrite){118int root_node = P.root[i][j];//⼦树根节点119if (root_node == P.root[1][P.n]){120//输出整棵树的根121 fileWrite << "k" << root_node << "是根" << endl;122 printOptimalBST(i, root_node - 1, root_node, P, fileWrite);123 printOptimalBST(root_node +1 , j, root_node, P, fileWrite);124return;125 }126127if (j < i - 1){128return;129 }else if (j == i - 1){//遇到虚拟键130if (j < r)131 fileWrite << "d" << j << "是" << "k" << r << "的左孩⼦" << endl;132else133 fileWrite << "d" << j << "是" << "k" << r << "的右孩⼦" << endl;134return;135 }136else{//遇到内部结点137if (root_node < r)138 fileWrite << "k" << root_node << "是" << "k" << r << "的左孩⼦" << endl; 139else140 fileWrite << "k" << root_node << "是" << "k" << r << "的右孩⼦" << endl; 141 }142 printOptimalBST(i, root_node - 1, root_node, P, fileWrite);143 printOptimalBST(root_node + 1, j, root_node, P, fileWrite);144 }145146//输出最优⼆叉查找树所有⼦树的根147void printRoot(Point P){148 cout << "各⼦树的根:" << endl;149for (int i = 1;i <= P.n;++i){150for (int j = 1;j <= P.n;++j){151 cout << P.root[i][j] << "";152 }153 cout << endl;154 }155 cout << endl;156 }157158int main(){159 file_read();160 optimalBST();161 ofstream fileWrite("out.dat");162 Point P ;163for(int i = 0; i<points.size(); i++) {164 P = points[i];165 printRoot(P);166 printOptimalBST(1,P.n,-1, P, fileWrite);167 }168 fileWrite.clear();169return0;170 } 上述代码是将给定的邻接矩阵从⽂件中读取 然后根据输⼊的邻接矩阵求出最短路径。
动态规划在最短路径问题中的应用

动态规划在最短路径问题中的应用动态规划是一种解决复杂问题的方法,它将问题分解成更小的子问题,并通过保存子问题的解来避免重复计算,从而提高解决问题的效率。
最短路径问题是在图或者网络中找到从起点到终点的最短路径的问题,可以使用动态规划算法来解决。
本文将介绍动态规划在最短路径问题中的应用及其算法实现。
一、最短路径问题在最短路径问题中,我们需要在图或网络中找到从一个节点到另一个节点的最短路径。
最短路径可以通过边的权重来衡量,权重可以表示距离、时间、代价等。
最短路径问题有多种变体,其中最常见的是单源最短路径和全源最短路径。
单源最短路径问题是在给定一个起点的情况下,找到该起点到其他所有节点的最短路径。
最常用的算法是Dijkstra算法和Bellman-Ford算法。
二、动态规划原理动态规划通过保存子问题的解来避免重复计算,从而提高算法的效率。
它将问题分解成更小的子问题,并使用递推关系来计算子问题的解。
在最短路径问题中,我们可以使用动态规划来计算从起点到每个节点的最短路径。
首先,我们定义一个一维数组dist[]来保存从起点到每个节点的最短路径长度。
初始化时,dist[]的值为无穷大,表示路径长度未知。
然后,我们从起点开始逐步计算每个节点的最短路径长度。
具体的动态规划算法如下:1. 初始化dist[]为无穷大,起点的dist[]为0。
2. 对于每个节点v,按照拓扑顺序进行如下操作:2.1. 对于节点v的所有邻接节点u,如果dist[v] + weight(v, u) < dist[u],则更新dist[u]。
2.2. 拓扑顺序可以根据节点的拓扑顺序进行计算或者使用深度优先搜索(DFS)算法。
三、算法实现下面是使用动态规划算法解决最短路径问题的示例代码:```// 定义图的邻接矩阵和节点个数int graph[MAX][MAX];int numNodes;// 定义dist[]数组来保存最短路径长度int dist[MAX];// 定义拓扑排序和DFS算法需要的变量bool visited[MAX];stack<int> s;// 动态规划算法求解最短路径void shortestPath(int startNode) {// 初始化dist[]数组为无穷大for (int i = 0; i < numNodes; i++) {dist[i] = INT_MAX;}dist[startNode] = 0;// 拓扑排序或DFS计算每个节点的最短路径长度 for (int i = 0; i < numNodes; i++) {if (!visited[i]) {DFS(i);}}// 输出最短路径长度for (int i = 0; i < numNodes; i++) {cout << "Node " << i << ": " << dist[i] << endl; }}// 深度优先搜索void DFS(int node) {visited[node] = true;for (int i = 0; i < numNodes; i++) {if (graph[node][i] != 0 && !visited[i]) {DFS(i);}}s.push(node);}```以上示例代码演示了使用动态规划算法求解最短路径问题的基本原理和步骤。
动态规划——所有点对最短路径问题

动态规划——所有点对最短路径问题按照书上所说,d k i ,j 代表了点i 到 j 经过 1or 2or 3or 4......k 的最短路径长度,⽐如d 31,6表⽰点1到点6, 可以经过点1,点2,点3的最短长度。
算法基本思路:引理,点 i 到点 j 的最短路径可能是点 i 到点 j 的直接路径长度,也可能是以某点 k 为中间节点,i, k, j 的路径长度。
采⽤⾃底向上逐步求解的⽅法,设D k i ,j表⽰ 点 i 到 j 以点集[0..k] 为中间节点的最短路径。
k 从0开始枚举各点,则第⼀步先求所有点以可能经过点0为中间节点的最短路径;第⼆步求所有点以可能经过点1为中间节点的最短路径,在此时所有的D[i, j] 已经考虑过0作为中间节点的最短路径,即第⼆步做的是以点集[0..1]作为考虑,满⾜⾃底向上,不难看出,到了最后⼀步,就是以点集[0...n-1]作为考虑,此时求得的D[i, j] 就是最短路径。
如:初始: k = 0298061∞6先代⼊公式 k = 0时,有 D 0[i ,j ]=L [i ,j ]; 所以有 D 0=0298061∞0[][]Processing math: 100%之后计算D1, 按照公式有 D1=min(D0[i,j],D0[i,k]+D0[k,j])所以D1=029 806 130以此类推,当计算到D3时,说明已经是经过整个点集的最短路径以下是python代码实现:n = 3 //n*n的矩阵D = [[0, 2, 9],[8, 0, 6],[1, 9999999, 6]]for k in range(0, 3): //从D_0到D_k进⾏k次运算for i in range(0, 3): //i从0到3for j in range(0, 3): //j从0到3,给每条边赋值D[i][j] = min(D[i][j], D[i][k] + D[k][j])print(D) //打印矩阵[]。
最短路径问题的动态规划算法

最短路径问题的动态规划算法动态规划是一种解决复杂问题的有效算法。
最短路径问题是指在给定的图中找到从起点到终点路径中距离最短的路径。
本文将介绍动态规划算法在解决最短路径问题中的应用。
1. 最短路径问题简介最短路径问题是图论中的经典问题之一,旨在找到从图中一点到另一点的最短路径。
通常使用距离或权重来衡量路径的长度。
最短路径问题有多种算法可以解决,其中动态规划算法是一种常用且高效的方法。
2. 动态规划算法原理动态规划算法的核心思想是将原问题分解为更小的子问题,并存储已解决子问题的结果,以供后续使用。
通过逐步解决子问题,最终得到原问题的解。
在最短路径问题中,动态规划算法将路径分解为多个子路径,并计算每个子路径的最短距离。
3. 动态规划算法步骤(1)定义状态:将问题转化为一个状态集合,每个状态表示一个子问题。
(2)确定状态转移方程:通过递推或计算得到子问题之间的关系,得到状态转移方程。
(3)确定初始状态:设置与最小子问题相关的初始状态。
(4)递推求解:根据状态转移方程,逐步计算中间状态,直到得到最终解。
(5)回溯路径:根据存储的中间状态,找到最短路径。
4. 动态规划算法示例以经典的Dijkstra算法为例,演示动态规划算法在解决最短路径问题中的应用。
假设有带权重的有向图G,其中节点数为n,边数为m。
算法步骤如下:(1)定义状态:对于图G中的每个节点v,定义状态d[v]代表从起点到节点v的最短距离。
(2)确定状态转移方程:d[v] = min(d[u]+w[u,v]),其中u为节点v 的直接前驱节点,w[u,v]为边(u,v)的权重。
(3)确定初始状态:设置起点s的最短距离d[s]为0,其他节点的最短距离d[v]为无穷大。
(4)递推求解:根据状态转移方程逐步计算中间状态d[v],更新最短距离。
(5)回溯路径:根据存储的前驱节点,从终点t开始回溯,得到最短路径。
5. 动态规划算法的优缺点优点:(1)求解速度快,适用于大规模问题。
基于动态规划的最短路径算法设计与优化

基于动态规划的最短路径算法设计与优化一、绪论最短路径问题是一个经典的计算机科学问题,在众多领域中都有着广泛的应用,如网络路由、物流配送、地图导航等。
本文将讨论如何运用动态规划方法来求解最短路径问题,并从算法设计和算法优化两个方面入手,提高算法的效率和性能。
二、最短路径问题的动态规划解法1. 最短路径的定义在一张有向带权图中,从起点s到终点t的一条路径,如果它的边权之和最小,那么我们称这条路径是最短路径。
2. 最短路径问题的动态规划解法基本原理我们可以将最短路径问题转化为子问题,定义d[v]表示从起点s到顶点v的最短距离,那么d[t]就是问题的解。
记G=(V,E)为一张有向带权图,我们要求的就是d[t]。
在进行最短路径的动态规划时,我们主要运用的是最优子结构和重复计算问题。
最优子结构的原理如下:一条最短路径可以被拆分为多个“次优解”,每个“次优解”都可以用更小的“次优解”组合而成,直到组合到最短路径为止。
重复计算问题的原理如下:在计算d[v]时,需要先计算出所有以v为终点的边的起点u的最短路径,这些最短路径构成了一个集合P。
如果直接使用暴力算法,则有可能会重复计算P中的某些路径。
运用动态规划,我们可以将已经计算出的最短路径结果保存起来,每次需要计算时可以直接调用,避免了重复计算的问题。
3. 最短路径问题的动态规划解法步骤定义数组d[V],其中d[s]=0,d[v]=+ɛ(v≠s)。
按拓扑排序的顺序遍历有向带权图,对于每个顶点v,更新所有以v为终点的边的起点u的最短路径,即:d[v]=min(d[u]+w[u,v]),其中w[u,v]表示边(u,v)的权值。
4. 最短路径问题的动态规划算法实现算法实现的代码如下:void dp_shortest_path(Graph *G, int s, int *d) {int t, i, v, u, p;for (i = 0; i < G->vexnum; ++i) d[i] = INF;d[s] = 0;for (t = 1; t < G->vexnum; ++t) {for (v = 0; v < G->vexnum; ++v) {for (p = G->v[v].first; p != -1; p = G->arc[p].next) {u = G->arc[p].adjvex;if (d[u] + G->arc[p].weight < d[v]) {d[v] = d[u] + G->arc[p].weight;}}}}}三、最短路径算法的优化1. Dijkstra算法优化Dijkstra算法是一种贪心算法,它适用于有权图的最短路径问题,算法的基本思路是:每次找到离起点最近的尚未确定最短路径的顶点v,更新v的所有邻接点的距离,直到找到终点或路径无法更新为止。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
10
15.4 最长公共子序列-最长公 共子序列的结构
穷举搜索法:对X的每一个子序列,检查它是否也是Y的子序 列,并且在检查过程中选出最长的公共子序列。 X共有2m个不同子序列,从而穷举搜索法需要指数时间。 应用问题:DNA序列相似性 DNA序列可以表示为有穷集合{A, C, G, T}上的一个串。 S1=ACCGGTCCCCAAACCTTGGGGGGAAACCCT, S2=CCCCGGGTTCCCGGGTGGGGGAAACCCCT, 找出第三个序列S3,在S3中的基也都出现在S1和S2中;而且 这种基必须是以相同的顺序出现,但是不必要时连续的。 这样的S3越长,S1和S2越相似。
2
第十五章 动态规划
本章主要内容:
动态规划介绍 装配线调度问题 矩阵链相乘问题 动态规划问题关键特征 背包问题(补充) 最长公共子序列 最优二叉查找树
每对顶点间的最短路径(第25章)
3
动态规划
设计一个动态程序算法的过程为:
刻划最优解的结构(最优子结构) 递归定义最优解的值(动态规划设计) 按自底向上的方式计算最优解的值(重叠?) 由计算出的结果构造一个最优解(可省略)
背包问题——分析
复杂度:O(nW) pseudo-polynomial
因为输入的大小不是nW,是nlogW。
自底向上还是自顶向下?
如果是自顶向下的调用?——自顶向下更高 效。 如果wi不是整数,而是实数?——自底向上 不可能。
9
15.4 最长公共子序列
一个给定序列的子序列是在该序列中删去若干元素后得 到的序列。确切地说,若给定序列X=<x1, x2,…, xm>, 则另一序列Z=<z1, z2,…, zk>是X的子序列是指存在一个 严格递增的下标序列 <i1, i2,…, ik>,使得对于所有 j=1,2,…,k,有 x i j = zj。当另一序列Z既是X的子序列又 是Y的子序列时,称Z是序列X和Y的公共子序列。 最长公共子序列(LCS)问题:给定两个序列X=<x1, x2, …, xm>和Y=<y1, y2, … , yn>,要求找出X和Y的一个 最长公共子序列。
第八讲:动态规划与最短路径(2)
《算法与算法复杂性》2011年春季 赵颖
Tentative Schedule
Date 2月23 3月2 3月9 3月16 3月23 3月30 4月6 4月13 4月20 4月27 5月4 5月11 5月18 5月25 6月1 6月8 Content Category HW HW(i)在布置HW(i+1) 课程基本情况+引言 基本设计与分析 算法入门+函数增长 基本设计与分析 HW1 那周交,过期不候; 分治策略 +递归分析 基本设计与分析 HW2 9次作业取成绩最好的6 排序和顺序统计学 基本设计与分析 HW3 次; 图的基本算法 基本设计与分析 HW4 上机题额外加分。 概率分析+随机算法 高级分析技术 HW5 平摊分析+优先队列 高级分析技术 HW6 动态规划 高级设计技术 动态规划 高级设计技术 HW7 bonus(上机题,考前交) 最短路径+贪心算法 高级设计技术 //////////////////////// /////////////// /////////////////// 贪心算法+图上复杂算法 高级设计技术 贪心算法+图上复杂算法 高级设计技术 HW8 NP复杂性问题 专题 近似算法 专题 HW9 review 过期的作业统一保存在FIT 3-126,大家随时可以去取。
17
15.4 最长公共子序列-构造最 长公共子序列
由算法LCS_LENGTH计算得到的数组b可用于 快速构造序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的最长公共子序列。从b[m,n]开始,沿着其 中的箭头所指的方向在数组b中搜索。
0 c[i, j ] c[i 1, j 1] 1 max(c[i, j 1], c[i 1, j ])
如果i,j>0且xi y j 如果i,j>0且xi y j i 0或j 0
15
15.4 最长公共子序列-计算最 优值
直接利用上式容易写出一个计算c[i,j]的递归算法,但其 计算时间是随输入长度指数增长的。由于在所考虑的子 问题空间中,总共只有θ(m*n)个不同的子问题,因此, 用动态规划算法自底向上地计算最优值能提高算法的效 率。 计算最长公共子序列长度的动态规划算法 LCS_LENGTH(X,Y) 输入:X=<x1, x2, …, xm> Y=<y1, y2, …, yn> 输出:c[0..m ,0..n]和b[1..m ,1..n]。其中c[i,j]存储Xi 与Yj的最长公共子序列的长度,b[i,j]记录指示c[i,j]的 值是由哪一个子问题的解达到的,这在构造最长公 共子序列时要用到。 X和Y的最长公共子序列的长度记录于c[m,n]中。
16
15.4 最长公共子序列-计算最 优值
LCS-LENGTH(X, Y) 1 m ← length[X] 2 n ← length[Y] 3 for i ← 1 to m 4 do c[i, 0] ← 0 5 for j ← 0 to n 6 do c[0, j] ← 0 7 for i ← 1 to m 8 do for j ← 1 to n 9 do if xi = yj 10 then c[i, j] ← c[i - 1, j - 1] + 1 11 b[i, j] ← "↖― 12 else if c[i - 1, j] ≥ c[i, j - 1] 13 then c[i, j] ← c[i - 1, j] 14 b[i, j] ← "↑" 15 else c[i, j] ← c[i, j - 1] 16 b[i, j] ← " ← " 17 return c and b 。
1.若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的一个 LCS; 2.若xm≠yn,那么zk≠xm 蕴含Z是Xm-1和Y的一个LCS; 3.若xm≠yn,那么zk≠yn 蕴含Z是X和Yn-1的一个LCS。
其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn1>,Zk-1=<z1, z2, …, zk-1>。
例如:w=50
a1(10,60) a2(20,100) a3(30,120)
5
背包问题——递归关系
满足最优子结构:
如果从最优解中取走aj,那么最优解中的剩余部分是剩 余子问题(背包容量为w-wj)的最优解(反证法)
递归关系:
令Ziu表示子问题(从������1 , ������2 , … , ������������ 中选择总重量小于u) 的最优解。 情况一:ai属于这个最优解,那么去掉ai剩余的子问题 变为从������1 , ������2 , … , ������������−1 中选择总重量小于u-wi Ziu=Zi-1,u-wi+vi 情况二: ai不属于这个最优解,Ziu=Zi-1,u Ziu从上述两种情况中选择一个最大值即可。
由此递归结构容易看到最长公共子序列问题具有子问题 重叠性质。例如,在计算X和Y的最长公共子序列时,可 能要计算出X和Yn-1及Xm-1和Y的最长公共子序列。而这两 个子问题都包含一个公共子问题,即计算Xm-1和Yn-1的最 长公共子序列。
14
15.4 最长公共子序列-一个递 归解
设c[i,j]记录序列Xi和Yj的最长公共子序列的长度。 其中Xi=<x1, x2, …, xi>,Yj=<y1, y2, …, yj>。当 i=0或j=0时,空序列是Xi和Yj的最长公共子序列, 故c[i,j]=0。其他情况下,可建立递归关系如下:
用循环填表:
表中的项:子问题的最优解 循环嵌套的层数=表格的维度(子问题分解的维度)+1( 如果做选择时需要) 循环的初始值:平凡子问题之外的最小子问题(需用递归 求解的最小子问题)。 循环增量方向:例如从左上向右下方填表,保证计算某个 子问题最优解时需要的表中的项都已求解。
4
背包问题
背包问题:
已知n个物品:������1 , ������2 , … , ������������ 其重量分别为: ������1 , ������2 , … , ������������ 其价值分别为: ������1 , ������2 , … , ������������ 背包的总容量为:w 求物品的一个子集使得总重量不超过w,并且总价值 最大。 0/1背包问题:物品取or不取 Fractional背包问题:每个物品可以取一部分
11
15.4 最长公共子序列-最长公 共子序列的结构
事实上,最长公共子序列问题也有最优子结构性 质,因为我们有如下定理: 定理15.1: LCS的最优子结构性质 设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一 个最长公共子序列Z=<z1, z2, …, zk>,则:
12
15.4 最长公共子序列-最长公 共子序列的结构
证明:用反证法。 1.若zk≠xm,则<z1, z2, …, zk ,xm >是X和Y的长度为k十1的公 共子序列。这与Z是X和Y的一个最长公共子序列矛盾。因 此,必有zk=xm=yn。由此可知Zk-1是Xm-1和Yn-1的一个长度 为k-1的公共子序列。因为若Xm-1和Yn-1有一个长度大于k1的公共子序列W,则将xm加在其尾部将产生X和Y的一个 长度大于k的公共子序列。此为矛盾。故Zk-1是Xm-1和Yn-1 的一个最长公共子序列。 2.由于zk≠xm,Z是Xm-1和Y的一个最长公共子序列。若Xm-1和 Y有一个长度大于k的公共子序列W,则W也是X和Y的一 个长度大于k的公共子序列。这与Z是X和Y的一个最长公 共子序列矛盾。由此即知Z是Xm-1和Y的一个最长公共子序 列。 3.与 2.类似。