动态规划算法的理解、编程题的讨论及结对编程情况

算法第三章作业

一、 动态规划算法

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个游艇出租站12...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

三、 结对编程情况

先互相探讨做题思路,做不出来的时候就上网看一些博客拓展思路,找出解决问题的办法;而后,再共同探究并寻找其他的优化算法,俩人互相分享信息。

posted @ 2018-11-04 21:48  Wayne-  阅读(376)  评论(0编辑  收藏  举报