算法第三章作业

本文深入解析动态规划算法的核心思想,包括最优子结构性质、重叠子问题性质及备忘录方法,通过例题详细分析动态规划算法的设计步骤,如最长单调递增子序列和租用游艇问题,提供C和Java代码实现。

1、对动态规划算法的理解

(1)基本思想:

动态规划算法的基本思想与分治法类似:将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解中得到原问题的解。但是,与分治法不同的是,为了避免重复多次计算子问题,动态规划算法用一个表记录所有已解决的子问题的答案,不管该子问题以后是否被利用,只要它被计算过,就将其结果填入表中。

(2)设计动态规划算法的步骤:

①找出最优解的性质,并刻画其结构特征

②递归地定义最优值

③以自底向上的方式计算最优值

④根据计算最优值时得到的信息构造最优解

(3)动态规划算法的基本要素

最优子结构性质

当问题的最优解包含了子问题的最优解时,称该问题具有最优子问题结构。在动态规划算法中,利用问题的最优子结构性质,以自底向上的方式递归地从子问题的最优解逐步构造出整个问题的最优解。

重叠子问题性质

在用递归算法自顶向下解决问题时,每次产生的子问题并不总是新问题,有些子问题可能被反复计算多次。动态规划算法利用这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,当再次需要解此子问题时,只需要简单地用常数时间查看一下结果即可。

从一般意义上讲,问题所具有的最优子结构性质和重叠子问题性质是该问题可用动态规划算法求解的基本要素。

备忘录方法

备忘录方法是动态规划算法的变形。与动态规划算法一样,备忘录方法用表格保存已解决的子问题的答案,在下次解决问题时,只要简单地查看该子问题的解答,不必再次计算。与动态规划算法不同的是,备忘录方法的递归方式是自顶向下的,而动态规划算法则是自底向上的。

备忘录方法为每个子问题建立一个记录项,初始化时,该记录项存入一个特殊的值,表示该子问题尚未求解。在求解的过程中对每个待求解的子问题,首先查看相应的记录项。若记录项存储的是初始化的特殊值,则需要计算该子问题的解,并保存在相应的记录项中已备以后查看。若记录项存储的不是初始值,则表示该子问题已被计算过,此时记录项存储的值即该子问题的解答。

 

2、例题的递归方程分析

7-1 单调递增最长子序列 (20 分)

设计一个O(n2)时间的算法,找出由n个数组成的序列的最长单调递增子序列。

输入格式:

输入有两行: 第一行:n,代表要输入的数列的个数 第二行:n个数,数字之间用空格格开

输出格式:

最长单调递增子序列的长度

输入样例:

在这里给出一组输入。例如:

5
1 3 5 2 9

输出样例:

在这里给出相应的输出。例如:

4

代码(C):#include <stdio.h>

#define MAX_N 1000
int dp[MAX_N], a[MAX_N];
int n;
void input()
{
    scanf("%d", &n);
    for(int i = 0; i < n; ++i)
        scanf("%d", &a[i]);
}
int max_(int a, int b)
{
    return a > b ? a : b;
}
void slove()
{
    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\n", res + 1);
}
int main()
{
    input();
    slove();
    return 0;
}


7-2 租用游艇问题 (17 分)

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i<j<=n。试设计一个算法,计算出从游艇出租站1 到游艇出租站n所需的最少租金。

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3
5 15
7

输出样例:

在这里给出相应的输出。例如:

12

代码(java):

import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
int n;
int[][] fee;
while (true){
  n = input.nextInt();
  fee = new int[n][n];
for(int row=0; row<n-1; row++)
for(int col=row+1; col<n; col++)
fee[row][col] = input.nextInt();
for(int k=2; k<n; k++)
for(int i=0; i<n-k; i++){
int j = i+k;
for(int p =i+1; p<j; p++){
int tmp = fee[i][p] + fee[p][j];
if(fee[i][j] > tmp)
fee[i][j] = tmp;
}
}
System.out.println(fee[0][n-1]);
}
}
}
3、说明结对编程情况
通过网上搜索怎么运用动态规划算法来分析和完成题目,和小伙伴一起认真地讨论题目的内容,研究了到底什么是动态规划算法,
再尽量地去理解它的思想之后,一起完成这两道编程题。
 

转载于:https://www.cnblogs.com/wanghaopeng/p/9863893.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值