采药(动态规划背包问题总结)

做了NOIP的题,是动态规划背包问题的典例。

采药

输入格式:

第一行有2个整数T(1T1000)和M(1M100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。

接下来的M行每行包括两个在1100之间(包括1100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式:

 1个整数,表示在规定的时间内可以采到的草药的最大总价值。

 

 

状态转移方程:

vis[i][j]=vis[i-1][j-xt[i]]+xw[i],当j>=xt[i];
vis[i][j]=vis[i-1][j],当j<xt[i];

其中vis[i][j]表示采摘前i个药时最大花费j时所能得到的最大价值,xw[i]是第i个药的价值,xt[i]是第i个药的费时。

代码如下:

for(int i=1;i<=m;i++)
    for (int j = 1;j <= t;j++)
    {
        if (j >= xt[i])
            vis[i][j] = max(vis[i - 1][j - xt[i]] + xw[i], vis[i - 1][j]);
        else
            vis[i][j] = vis[i - 1][j];
    }

 我们可以发现,vis数组每次i递进1时只用到上一层的i-1,所以可以用滚动数组替换,因为大的j(vis[i][j])在计算时要用到小的j(vis[i-1][j-?]),故要从t向下开始替换,以免替换之前的vis[i-1][?]被换成了vis[i][?]。状态转移方程如下:

vis[j]=vis[j-xt[i]]+xw[i],当j>=xt[i];
vis[j]=vis[j],当j<xt[i];

代码如下:

for(int i=1;i<=m;i++)
    for (int j = t;j >= 1;j--)
    {
        if (j >= xt[i])
            vis[j] = max(vis[j - xt[i]] + xw[i], vis[j]);
        else
            vis[j] = vis[j];
    }

   又做了一个题,其中每种药的个数不限制,这样一来又要套一个循环vis[i][j]=max(vis[i-1][j-n*xt[i]]+n*xw[i],vis[i-1][j])其中n为选择该药的数量。

但提交后发现超时了,看了题解,发现可以用vis[j]=max(vis[j-xt[i]]+xw[i],vis[j])替换掉循环,其中vis[j-xt[i]]为替换过的值,实际上递推代替循环,但注意要从小的j到大的j更新vis的值,使得使用的vis[j-xt[i]]是被替换过的。

代码如下:

    for(int i=1;i<=m;i++)
        for (int j = 1;j <= t;j++)
        {
            if(j>=xt[i])
                vis[j] = max(vis[j - xt[i]] + xw[i], vis[j]);
        }

 

转载于:https://www.cnblogs.com/chendie/p/10454179.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值