动态规划-01背包(1)

        bp,就是backpack问题,背包问题,也可以称作是knapsack问题。

        首先是最简单的背包问题,连续性背包问题,主要用的是贪婪算法(greedy algorithm)。


Problem:

        你是一个小偷,有8磅重的背包,你进入了一个人的家里,看到了3kg的金沙,4kg的银子,10kg的葡萄干。你有一个8kg的背包,你应该怎么拿使价值最大。

Answer:

       典型的贪婪算法,先3kg金子,再4kg银子,再1kg葡萄干。不给出代码_(:з」∠)_


        上面的这个问题,可以说是一个连续的问题,

        而接下来的问题,涉及到了动态规划dynamic programming

        动态规划涉及到两个问题:一个是找到重叠子,二是最优子结构。


        讨论一下重叠子,其实就是重叠的部分,这里面最典型的例子就是递归。斐波拉契数列用递归计算的话,里面就有很多重叠的地方。假设我们知道第一个和第二个,如果我们要算第n个,那么我们只需要计算n-2次,而递归的机制就很麻烦,不说机制,数据说明一切。

        n从3开始到10,次数依次是3 5 9 15 25 41 67 109,当n到30的时候,次数就达到了1664079,这样的计算方式是很耗费时间的,这在ACM这个抢时间的游戏中是不适用的。因为这之中有太多的重叠的地方。这时其实有个很简单的改变,把重复使用的数据“缓存”下来即可。

       原递归斐波拉契数列函数:

      

int fab(int a){
    if(a==1 || a==2)
        return 1;
    else
        return (f(a-1)+f(a-2));
}
      
       这种递归的方式速度慢,所以不采纳。
       至于更改,采用迭代,从最小的开始就好了。



       正式进入正题,动态规划。

       当有一个最优子结构,并且局部解决方案有重叠时,就可以考虑采取动规。

       现在讨论01背包的问题,就用我们oj上的题目采药1033

       先手动的写一张图出来,就用我们sample的数据,这里仔细叙述流程。

       1.在山洞里只有5株草药,我们编号1到5,分别对应1到5行,每一株都有各自的采摘时间和价值。

       2.从5号草药开始,我们从表格从左往右写,99和100是90,其余的都是0。

       3.类推2,写出4号,0到49是0,50到92是46,而99和100,还是90,因为90比较大。

       4.类推3,就可以找出一个递推式。

       我们设整个的价值表格是c[M][T],M就是草药的棵数,草药一棵棵的来,在设定两个一维数组,t[M]和v[M],分别存储的是草药的采摘时间和价值,这样我们从第一株开始,也就是M=1,M++。每次循环是T=0,T++。

       则可以得到表达式:

      c[M][T] = max(c[M+1][T], c[M+1][T+t[M]]+v[M])

       动态规划的题主要就是找到上面这个表达式,我们取消掉仅做参考用的M,只使用一维数组,下面列出代码:

#include<iostream>
using namespace std;
#define max(a,b) ((a)>(b)?(a):(b))

int main(){
    int c[1001] = {0};
    int T, M, i, j ,v, n;
    cin>>T>>M;
    for(i=1; i<=M; i++){
        cin>>n>>v;
        for(j=T; j>=n; j--)
            if(c[j-n] + v > c[j])
                c[j] = c[j-n] + v;
    }
    cout << c[T] << endl;
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值