动态规划算法的理解、编程题的讨论及结对编程情况
算法第三章作业
一、 动态规划算法
1.介绍:
动态规划算法与分治法类似,其基本思想也是将待求问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
与分治法不同的是,适合与动态规划法求解的问题,经分解得到的子问题往往不是互相独立。若用分治法解决这类问题,则分解得到的子问题数目太多,以至于最后解决原问题需要耗费指数时间。然而,不同子问题的数目常常只有多项式量级。
在用分治法求解时,有些子问题被重复计算了许多次。如果我们能保存已解决问题的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,从而得到多项式时间算法。
为了达此目的,可以用一个表来记录所有已解决的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其填入表中。
这就是动态规划法的基本思想。具体的动态规划算法多种多样,但它们具有相同的填表格式。
2.动态规划算法适用于求解最优化问题,通常可按以下4个步骤设计:
(1)找出最优解的性质,并刻画其结构特征。
(2)递归地定义最优值。
(3)以自底向上的方式计算出最优值。
(4)根据计算最优值时得到的信息,构造最优解。
二、 编程题的递归方程
1.单调递增最长子序列
(1)问题描述:设计一个O(n2)时间的算法,找出由n个数组成的序列的最长单调递增子序列。
(2)代码如下:
#include <stdio.h>
#define MAX_N 1000
int dp[MAX_N], a[MAX_N];
int n;
int max(int a, int b){
return a > b? a: b;
}
int main(){
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
int res = 0;
for (int i = 0; i < n; i++){
for (int j = 0; j < i; j++){
if (a[j] < a[i])
dp[i] = max(dp[i], dp[j] + 1);
}
res = max(dp[i], res);
}
printf("%d", res + 1);
return 0;
}
(3)递归方程,时间、空间复杂度如下:
①递归方程:
dp[i] = max(dp[i], dp[j] + 1); a[j] < a[i];
②时间复杂度:O(n2),空间复杂度:O(n)
(4)拓展:设计一个O(nlogn)时间的算法,找出由n个数组成的序列的最长单调递增子序列。
(5)代码如下:
#include <stdio.h>
using namespace std;
int a[1005], b[1005];
int binary_search(int len, int i){
int first = 1, last = len;
while(first < last){
int mid = first + (last - first) / 2;
if (b[mid] >= a[i])
last = mid;
else
first = mid + 1;
}
return first;
}
int main(){
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
b[1] = a[0];
int len = 1;
for (int i = 1; i < n; i++){
if (a[i] > b[len]){
b[++len] = a[i];
}
else {
int j = binary_search(len, i);
b[j] = a[i];
}
}
printf("%d\n", len);
return 0;
}
(6)递归方程,时间、空间复杂度如下:
①递归方程:
b[++len] = a[i]; a[i] > b[len];
b[j] = a[i]; a[i] <= b[len];
②时间复杂度:O(nlogn),空间复杂度:O(n)
2.租用游艇问题
(1)问题描述:长江上设置了n个游艇出租站1,2...n。游艇出租站i到游艇出租站j之间的租金为r(i, j), 1<=i <j<=n。试设计一个算法,计算出从游艇出租站1到游艇出租站n所需的最少租金。
(2)代码如下:
#include <stdio.h>
int r[200][200] = {0};
int p[200][200] = {0};
int answer[200] = {0};
int smallestFee(int start, int n){
if (start == n){
p[start][n] = r[start][n];
return 0;
}
int smallest = 1 << 10;
int x;
for (int k = start + 1; k <= n; ++k){
int temp = r[start][k];
if (p[k][n] != 0)
temp += p[k][n];
else
temp += smallestFee(k, n);
if (temp < smallest){
smallest = temp;
x = k;
}
}
answer[x] = x;
p[start][n] = smallest;
return smallest;
}
int main(){
int n;
scanf("%d", &n);
for (int i = 1; i <= n - 1; ++i){
for (int j = i + 1; j <= n; ++j){
scanf("%d", &r[i][j]);
}
}
printf("%d\n", smallestFee(1, n));
return 0;
}
(3)递归方程,时间、空间复杂度如下:
①递归方程:
p[start][n] = r[start][n]; start = n; // 备忘录
temp = r[start][k];
temp += p[k][n]; p[k][n] != 0;
temp += smallestFee(k, n); p[k][n] == 0;
②时间复杂度:O(n2),空间复杂度:O(n2)
3.1.参考链接1:
(1)https://blog.csdn.net/fangxiaxin/article/details/80595797
(2)https://blog.csdn.net/qq_42459319/article/details/80786333
(3)https://blog.csdn.net/ldw201510803006/article/details/68954395
(4)https://ask.csdn.net/questions/685965
(5)http://www.cnblogs.com/mycapple/archive/2012/08/22/2651453.html
3.2.参考链接2:
(1)https://blog.csdn.net/gpltoken/article/details/52954073
(2)https://www.cnblogs.com/jacklovelol/p/6013111.html
(3)https://blog.csdn.net/Elenore1997/article/details/78363972
(4)http://blog.sina.com.cn/s/blog_69ada9e70100khuj.html
(5)https://blog.csdn.net/artprog/article/details/49886021
三、 结对编程情况
先互相探讨做题思路,做不出来的时候就上网看一些博客拓展思路,找出解决问题的办法;而后,再共同探究并寻找其他的优化算法,俩人互相分享信息。