动态规划

Posted zuofaqi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划相关的知识,希望对你有一定的参考价值。

基本思想

动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中, 可能会有很多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动规划算法与分治法类似,其基本思想也是将待求解问题分解为若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适用于动态规划算法求解的问题,经分解得到的子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算很多次。如果我们能保存已解决子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解决的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划算法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。

与分治法最大的差别是:适用于动态规划求解的问题,经分解后得到的子问题不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)

应用场景

适用于动态规划的问题必须满足最优化原理、无后效性和重叠性。

(1) 最优化原理(最优子结构性质):一个最优化策略具有这样的性质,不论过去状态和决策如何,对前面的决策所形成的状态而言,余下的决策必须构成最优策略。简而言之,一个最优化策略的子策略总是最优的。一个问题满足最优化原理又称其具有最优子结构性质。

(2) 无后效性:将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的状态无法直接影响它未来的决策,而只能通过当前的这个状态。换句话说,每个状态都是过去历史的一个完整总结。这就是无后向性,又称无后效性。

(3) 子问题的重叠性:动态规划将原来具有指数级时间复杂度的搜索算法改进成了具有多项式时间复杂度的算法。其中的关键在于解决冗余,这就是动态规划算法的根本目的。动态规划实质上是一种以空间换时间的技术,它在实现的过程中,不得不存储产生过程中的各种状态,所以它的空间复杂度要大于其他算法。

 

具体问题

01 背包问题:

有编号分别为a,b,c,d,e的五件物品,它们的重量分别是4, 6, 2, 2, 5, 1,它们的价值分别是8, 10, 6, 3, 7, 2,每件物品数量只有一个,现在给你个承重为12的背包,如何让背包里装入的物品具有最大的价值总和?

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

void dynamic(int N, int C, int* weight, int* value)
{
    int* arr = new int[C+1];
    int* prearr = new int[C+1];
    int* maxvalue = new int[N];

    for (int i=1; i<=C; i++)
    {
        prearr[i] = 0;
    }

    for (int n=0; n<N; n++)
    {
        for (int c=1; c<=C; c++)
        {
            if (weight[n] > c)
            {
                arr[c] = prearr[c];
            }
            else
            {
                arr[c] = max(prearr[c], prearr[c-weight[n]]+value[n]);
            }
        }
        maxvalue[n] = arr[C];
        for (int i=1; i<=C; i++)
        {
            prearr[i] = arr[i];
            printf("%3d  ", prearr[i]);

        }
        cout << endl;
    }
    for (int i=1; i<=C; i++)
    {
        printf("%3d  ", prearr[i]);
    }
    cout << endl;

    for (int i=N-1; i>0; i--)
    {
        if (maxvalue[i] != maxvalue[i-1])
        {
            cout << i << ‘	‘;
        }
    }
    if (maxvalue[0] != maxvalue[1])
    {
        cout << 0 << endl;
    }

    delete[] arr;
    delete[] prearr;
    delete[] maxvalue;
}

int main()
{
    int weight[] = {4, 6, 2, 2, 5, 1};
    int value[] = {8, 10, 6, 3, 7, 2};
    dynamic(6, 12,  weight, value);

    return 0;
}

 

运行结果:

 

  0    0    0    8    8    8    8    8    8    8    8    8  
  0    0    0    8    8   10   10   10   10   18   18   18  
  0    6    6    8    8   14   14   16   16   18   18   24  
  0    6    6    9    9   14   14   17   17   19   19   24  
  0    6    6    9    9   14   14   17   17   19   21   24  
  2    6    8    9   11   14   16   17   19   19   21   24  
  2    6    8    9   11   14   16   17   19   19   21   24  
2       1       0

 

  

 

以上是关于动态规划的主要内容,如果未能解决你的问题,请参考以下文章

是否可以动态编译和执行 C# 代码片段?

动态规划_线性动态规划,区间动态规划

应对笔试手写代码,如何准备动态规划?

应对笔试手写代码,如何准备动态规划?

应对笔试手写代码,如何准备动态规划?

算法动态规划 ⑤ ( LeetCode 63.不同路径 II | 问题分析 | 动态规划算法设计 | 代码示例 )