动态规划:装配线与LCS问题
2012-10-19 13:51
387 查看
1 概述
1、分治法和动态规划都是通过组合子问题的解来解决整个问题。
2、动态规划适用于各个子问题包含公共子问题的情况。
3、分治法将问题划分为一些独立的子问题。
2 动态规划算法设计思路
1、描述最优子结构
2、递归定义最优解的值
3、按自底向上的方式计算最优解的值
3 装配线调度问题
3.1 问题的描述
有如图的一条装配工厂,有两条并行的装配线,每个站点的处理时间是a(i,j),其中i=1,2,j=1...n。两个装配线间切换的时间为t(i,j)。
输出:在装配线上选择一条最快路径。
3.2 方法一、强力法
图中有两条并行的装配线,经过2^n种尝试,总可以找出最优解,但是时间复杂度很高。
3.3 方法二、动态规划
考虑其中的任意一个装配站a(i,j),离开装配站a(i,j)的时间可以表示为:(如i=1)
若问题是计算一个点的最短时间,这是一个递归的过程,具有O(n)的时间复杂度。但是如果需要知道最快路径,则如果从最后一个装配站开始向前递归,每一个节点j又必须向前递归j-1次,其中的子问题的解进行了多次的重复计算,因此复杂度认为O(2^n)。
由此引出了动态规划,将公共子问题(即离开某站a(i,j)的最短时间和上一节点值),则只需通过简单递归就可组合出最优解。
4 最长公共子序列
4.1 问题的描述
给定两个序列X={x1, x2,..., xm}和Y={y1, y2,.., yn},找出两个序列的最长公共子序列。
4.2 问题的分析
首先定义序列的前缀Xi和Yi。
接着定义最优子结构:设两个序列X={x1, x2,..., xm}和Y={y1, y2,.., yn},并设Z={z1, z2,..., zk}为X和Y的任意一个LCS
1)如果xm=yn,则zk=xm=yn,而且Zk-1是Xm-1和Yn-1的一个LCS
2)如果xm^=yn,且zk^=xm,而且Z是Xm-1和Yn的一个LCS
3)如果xm^=yn,且zk^=yn,而且Z是Xm和Yn-1的一个LCS
容易看出重叠子问题的性质,易得递归式
整个问题的最优解就是X序列的某个前缀和Y序列的某个前缀的LCS,因此容易得到动态规划的解
5 小结
动态规划问题的关键是寻找最优子结构,问题的一个最优解中包含了子问题的最优解,并分析重叠子问题,其中最关键的是写出上述的递归式,分析问题的递归性,然后才能找到子问题。
1、分治法和动态规划都是通过组合子问题的解来解决整个问题。
2、动态规划适用于各个子问题包含公共子问题的情况。
3、分治法将问题划分为一些独立的子问题。
2 动态规划算法设计思路
1、描述最优子结构
2、递归定义最优解的值
3、按自底向上的方式计算最优解的值
3 装配线调度问题
3.1 问题的描述
有如图的一条装配工厂,有两条并行的装配线,每个站点的处理时间是a(i,j),其中i=1,2,j=1...n。两个装配线间切换的时间为t(i,j)。
输出:在装配线上选择一条最快路径。
3.2 方法一、强力法
图中有两条并行的装配线,经过2^n种尝试,总可以找出最优解,但是时间复杂度很高。
3.3 方法二、动态规划
考虑其中的任意一个装配站a(i,j),离开装配站a(i,j)的时间可以表示为:(如i=1)
若问题是计算一个点的最短时间,这是一个递归的过程,具有O(n)的时间复杂度。但是如果需要知道最快路径,则如果从最后一个装配站开始向前递归,每一个节点j又必须向前递归j-1次,其中的子问题的解进行了多次的重复计算,因此复杂度认为O(2^n)。
由此引出了动态规划,将公共子问题(即离开某站a(i,j)的最短时间和上一节点值),则只需通过简单递归就可组合出最优解。
int _tmain(int argc, _TCHAR* argv[]) { int a[2][6] = {7, 9, 3, 4, 8, 4, 8, 5, 6, 4, 5, 7}; int t[2][5] = {2, 3, 1, 3, 4, 2, 1, 2, 2, 1}; int e1 = 2, e2 = 4, x1 = 3, x2 = 2; vector<LineNode> S1(6), S2(6); LineNode end; //构造子问题的解 for (int i = 0; i < 6; i++) { if (i == 0) { S1[i].Cost = e1 + a[0][0]; S2[i].Cost = e2 + a[1][0]; } else { int temp1 = (S1[i-1].Cost + a[0][i]), temp2 = (S2[i-1].Cost + t[1][i-1] + a[0][i]); if (temp1 < temp2) { S1[i].Cost = temp1; S1[i].preNode = 1; } else { S1[i].Cost = temp2; S1[i].preNode = 2; } int temp3 = (S2[i-1].Cost + a[1][i]), temp4 = (S1[i-1].Cost + t[0][i-1] + a[1][i]); if (temp3 < temp4) { S2[i].Cost = temp3; S2[i].preNode = 2; } else { S2[i].Cost = temp4; S2[i].preNode = 1; } } } for (int i = 0; i < 6; i++) cout << S1[i].Cost << " "; cout << endl; for (int i = 0; i < 6; i++) cout << S2[i].Cost << " "; cout << endl; int temp1 = (S1[5].Cost + x1), temp2 = (S2[5].Cost + x2); if (temp1 < temp2) { end.Cost = temp1; end.preNode = 1; } else { end.Cost = temp2; end.preNode = 2; } int flag = end.preNode; //输出最短路径 for (int i = 5; i>= 0; i--) { if (flag == 1) { cout << "S1, Node " << i << endl; flag = S1[i].preNode; } else { cout << "S2, Node " << i << endl; flag = S2[i].preNode; } } system("pause"); return 0; }
4 最长公共子序列
4.1 问题的描述
给定两个序列X={x1, x2,..., xm}和Y={y1, y2,.., yn},找出两个序列的最长公共子序列。
4.2 问题的分析
首先定义序列的前缀Xi和Yi。
接着定义最优子结构:设两个序列X={x1, x2,..., xm}和Y={y1, y2,.., yn},并设Z={z1, z2,..., zk}为X和Y的任意一个LCS
1)如果xm=yn,则zk=xm=yn,而且Zk-1是Xm-1和Yn-1的一个LCS
2)如果xm^=yn,且zk^=xm,而且Z是Xm-1和Yn的一个LCS
3)如果xm^=yn,且zk^=yn,而且Z是Xm和Yn-1的一个LCS
容易看出重叠子问题的性质,易得递归式
整个问题的最优解就是X序列的某个前缀和Y序列的某个前缀的LCS,因此容易得到动态规划的解
int n = 7, m = 6; char X[] = {'A', 'B', 'C', 'B', 'D', 'A', 'B'}; char Y[] = {'B', 'D', 'C', 'A', 'B', 'A'}; vector< vector<ListNode2> > cost(n + 1, m + 1); void LCS_Print(int i, int j); void LCS() { for (int i = 1; i < n+1; i++) { for (int j = 1; j < m+1; j++) { if (X[i-1] == Y[j - 1]) { cost[i][j]._length = cost[i - 1][j - 1]._length + 1; cost[i][j]._direction = UPLEFT; } else if (cost[i][j - 1]._length > cost[i - 1][j]._length) { cost[i][j]._length = cost[i][j - 1]._length; cost[i][j]._direction = LEFT; } else { cost[i][j]._length = cost[i - 1][j]._length; cost[i][j]._direction = UP; } } } for (int i = 0; i < 8; i++) { for (int j = 0; j < 7; j++) cout << "(" << cost[i][j]._length << ", " << cost[i][j]._direction << ") "; cout << endl; } LCS_Print(7, 6); } void LCS_Print(int i, int j) { if (i == 0 || j == 0) return; switch (cost[i][j]._direction) { case UPLEFT: LCS_Print(i - 1, j - 1); cout << X[i - 1] << " "; return; case LEFT: return LCS_Print(i, j - 1); case UP: return LCS_Print(i - 1, j); default: break; } }
5 小结
动态规划问题的关键是寻找最优子结构,问题的一个最优解中包含了子问题的最优解,并分析重叠子问题,其中最关键的是写出上述的递归式,分析问题的递归性,然后才能找到子问题。
相关文章推荐
- 动态规划: 装配线调度问题 (算法导…
- 动态规划解最长公共子序列问题LCS(二)
- 动态规划解最长公共子序列问题(LCS)C语言加注释
- 动态规划解决最长公共子序列LCS问题
- 流水线调度最优问题(装配线调度问题)动态规划 O(n)时间(线性时间)C++实现
- 动态规划--装配线调度问题
- 动态规划之 装配线调度问题
- 动态规划--装配线调度问题
- 装配线调度问题 算法导论动态规划P194
- 【经典问题】二维动态规划问题:求最长公共子序列LCS
- 动态规划相关问题源码(包括矩阵链乘、LCS、和max sum)
- 动态规划之最长公共子序列问题(LCS)
- 动态规划学习记录 二、装配线调配问题
- 动态规划--装配线调度问题
- 动态规划之最长公共子序列(LCS)问题
- 动态规划;最长公共子序列;LCS问题;
- 动态规划---LCS问题 最长公共子序列
- 动态规划 字符串最大公共子序列以及最大公共子串问题LCS
- 动态规划之装配线问题(递归实现)
- 流水线调度最优问题(装配线调度问题)动态规划 O(n)时间(线性时间)C++实现