动态规划(DP dynamic programming)

本文通过生动的例子,如计算加法、斐波那契数列和0-1背包问题,介绍了动态规划的基本思想和实现方法。文章展示了如何利用之前计算的结果来避免重复计算,从而提高算法效率。

今天上quora,看到一个有趣的问题:如何向四岁小朋友(外行)解释动态规划这个术语?如果别人首次听说c程序中的回溯概念,我们应该如何向他们解释这个术语?

下面是google程序员 Jonathan Paulson 的回复,获得了9900+赞

// 拿一张纸,写下 1+1+1+1+1+1+1+1=
“这个等于几?”
(计算中)“八”
(再在左侧补上1+)
“现在又等于几?”
(速度很快)“九”
“为什么你这么快就算到九呀?”
“你只加了一嘛”
“恩,你不需要全部重新计算,因为你记住了前面的结果是八。动态规划就是记住东西以节省后面时间的一种奇妙方法。”

斐波那契数列(Fibonacci Sequence)0, 1, 1, 2, 3, 5, 8, 13, 21...可以很容易用递归编程算出第n个数的值:

int fib(int n)
{
    //int a=0;b=1;
    if(n==0) return 0;
    if(n==1) return 1;
    return fib(n-1)+fib(n-2);
}

但是,这样递归会有大量的重复计算。以f(5)为例,f(5)=f(4)+f(3),而f(4)=f(3)+f(2)。这样,f(3)就被计算了两次。

DP动态编程就是将计算过的数据存储起来以备后用。

unsigned long fib2(int n)
{
    map<int,int> m;
    m[0]=0;
    m[1]=1;
    if(m.find(n)!=m.end())
    {
        return m[n];
    }
    else
    {
        return m[n]=fib(n-1)+fib(n-2);
    }

}

再举一例,0-1背包问题

//0-1 knapsack problem  
#include <iostream>
#include <vector>

using namespace std;

#define MAX_ITEMS 10  
#define MAX_CAPACITY 100

int knapsack(int value[], int weight[], int n, int C)  
{  
//For code simplicity, I'm creating a fixed size array.  
//Actually it should depend on n and C  
int M[MAX_ITEMS+1][MAX_CAPACITY+1] = {{0,},};  //initialize to zero  
int i, j;

for(i=1; i<= n; i++)  
{  
for(j=1; j<=C; j++)  
{  
    if(weight[i-1] > j)  
        M[i][j] = M[i-1][j];  
    else  
    {  
        M[i][j] = M[i-1][j];  
        if( (M[i-1][j-weight[i-1]]+value[i-1]) > M[i][j])  
            M[i][j] = M[i-1][j-weight[i-1]] + value[i-1];  
    }      
}  
}  
return M[n][C];  
}

//This main function is here just to show how to call knapsack()  
int main()  
{  
int value[6] = {3,6,7,9,11,18};  
int weight[6] = {1,2,3,5,6,8};  
int C = 100;  
vector<int> pos;  
int w = knapsack(value, weight, 6, 15);  
cout << w << endl;  
return 0;  
}


M(i,j)表示容量为j的背包装前i个物品所取得最优解,1<j<C,1<i<n,M(i,j)的计算如下:

M(i,j)的值有两种可能。

如果第i件物品不装进背包,则 M(i , j) = M(i - 1 , j).

如果第i件物品装进去,M(i , j) = M(i - 1 , j – si) + vi

最终,M(i , j) = max{ M(i - 1 , j) , M(i - 1 , j – si) + vi }

               0              if i = 0 or j = 0

M(i , j)   =    M(i-1, j)      if si > j

               max{ M(i - 1 , j) , M(i - 1 , j  si) + vi }   (otherwise)

最后算得当i=n,j=C即M(n,C)就是所求最优解。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值