【FBI WARNING】DP 从看透到看开

众(自)所(己)周(瞎)知(说) DP在NOIP应用的很多

动态规划算法通常基于一个递推公式及一个或多个初始状态。 当前子问题的解将由上一次子问题的解推出。使用动态规划来解题只需要多项式时间复杂度, 因此它比回溯法、暴力法等要快许多。

现在让我们通过一个例子来了解一下DP的基本原理。

首先,我们要找到某个状态的最优解,然后在它的帮助下,找到下一个状态的最优解。  ——by Hawstein


 

什么是动态规划?

     和分治法一样,动态规划(dynamic programming)是通过组合子问题而解决整个问题的解。

     分治法是将问题划分成一些独立的子问题,递归地求解各子问题,然后合并子问题的解。

     动态规划适用于子问题不是独立的情况,也就是各子问题包含公共的子子问题。

     此时,分治法会做许多不必要的工作,即重复地求解公共的子问题。动态规划算法对每个子问题只求解一次,将其结果保存起来,从而避免每次遇到各个子问题时重新计算答案。

适用范围

     最优性原理体现为问题的最优子结构特性。当一个问题的最优解中包含了子问题的最优解时,则称该问题具有最优子结构特性。

     最优性原理是动态规划的基础。任何一个问题,如果失去了这个最优性原理的支持,就不可能用动态规划设计求解。

     1.问题中的状态满足最优性原理。

     2.问题中的状态必须满足无后效性。

     所谓无后效性是指:“下一时刻的状态只与当前状态有关,而和当前状态之前的状态无关,当前状态是对以往决策的总结”。

                                                        ——by 剑仙

 对于它的设计 我感觉应该有两种方法:

   自顶向下(直接跑记忆化搜索):基本上对应着递归函数实现,从大范围开始计算,要注意不断保存中间结果,避免重复计算。

     自底向上(递推):从小范围递推计算到大范围。

DP有特别重要的两点:

1.写出方程。

2.确定边界。

 


举个栗子

一个人每次只能走一层楼梯或者两层楼梯,问走到第80层楼梯一共有多少种方法。

当我第一次看到这个题目的时候 感觉特别难 无从下手 仔细想想 还是有思路的

 

这个题是经典的一维动态规划。爬楼梯数目其实是一个斐波拉契数列。

 

假定f[i] 表示是爬到第i层的方法,那么f[i] = f[i-1] + f[i-2] //第i层的方法数目等于第i-1层数目加上第i-2层数目。

初值:f[0] = 1, f[1] = 1。 //最开始没有爬和第一层的方法数目为1.

输出:f[n] 爬到第n层的方法数目。

上代码:

#include <iostream>
using namespace std;
int f[10001] = {0};//初始化一下 避免后面出故障
int main()
{
    int num;
    cin>>num;//可以配合顶置帖子的那个读入优化写 本题无所谓 
    f[1] = 1;//爬到第一层只有一种方法:一次爬一个
    f[2] = 2;//爬到第二层有两种方法:一次爬一个、一次爬两个
    for(int i = 3; i <= num; i++)
        {
            f[i] = f[i-1] + f[i-2];//递推公式
    }
    cout<<f[num]<<endl;//到第sum层
    return 0;
}
    

 


有时间继续补充(逃

 

posted @ 2018-06-27 16:58  _Yrh  阅读(222)  评论(0编辑  收藏  举报