1/16 背包笑传之测测爆

1/16 背包笑传之测测爆

成绩(这次真爆了)

题目 P2871 [USACO07DEC] Charm Bracelet S P1049 [NOIP2001 普及组] 装箱问题 P1802 5 倍经验日 P2663 越越的组队 P1510 精卫填海 U524956 宠物小精灵之收服 P2946 [USACO09MAR] Cow Frisbee Team S
分数 82 100 90 50 10 0 10

前置知识(有点长,知识点梳理)

dp

dp的四步法(水字数)

  1. 确定状态
  2. 确定答案
  3. 确定状态转移方程
  4. 确定初始状态和边界

01背包

从名字上就很好理解, \(0\) 代表不选, \(1\) 代表选。

同时对应着dfs中的选和不选问题(驭澄音)。

这种问题一般有3种写法:

  1. 第一种就是最简单并且本人最会的暴搜,只要数据不大,优势在我。
  2. 第二种就是本人最不会的贪心。这里的贪心可贪多个值,比何坤还能贪
  3. (第三种写法在后面)。

接下来我们要用贪心的角度想一下这道题:

  1. 按照重量贪。

    容量10

    物品1 物品2 物品三
    重量 10 6 4
    价值 1 0.1 0.1

    重量贪:物品2+物品3=0.1+0.1=2

    正常:物品1=10

    直接过

  2. 按照价格贪。

    容量10

    物品1 物品2 物品三
    重量 10 6 4
    价值 10 8 4

    价格贪:物品1=10

    正常:物品2+物品3=8+4=12

    也过

  3. 按照性价比贪。

    容量10

    物品1 物品2 物品三
    重量 8 6 4
    价值 10 7 4
    性价比 1.25 0.86 1

    性价比贪:物品1=10

    正常:物品2+物品3=7+4=11

    也过

看得出来,贪心的每一个方法都有hack。

不藏了,我们现在直接拿出我们的dp吧。

温馨提示:

01背包属于多状态dp

时间复杂度: \(O(n*m)\)

空间复杂度: \(O(n*m)\)

题目

P2871 [USACO07DEC] Charm Bracelet S

这道题纯纯滚动背包版子。

滚动:

​ 就意思是指把dp数组降一个维度。

​ 要求就是dp数组只会取上一此算的数据,否则会出现“答案失踪案件”

​ 所以还是先写完正常版本,再写滚动优化

  1. 确定状态:

    pre[j]代表dp[i - 1][j],上一次的价值
    dp[j]代表dp[i][j],这一次的价值
    
  2. 确定答案

    dp[m],最后算出来的数据
    
  3. 确定状态转移方程

    放不下:dp[j] = pre[j];
    放得下:dp[j] = max(pre[j], pre[j - w[i]] + val[i]);
    
  4. 确定初始状态和边界

    dp和pre都为0
    

P1049 [NOIP2001 普及组] 装箱问题

这个比上面那题更简单,最大值问题。

  1. 确定状态:

    dp[i - 1][j]代表上一次的占地空间
    dp[i][j]代表这一次的占地空间
    
  2. 确定答案

    求出最后一次的最大值,用容量减去最大值算出来的剩余空间为答案
    
  3. 确定状态转移方程

    放不下:dp[i][j]=dp[i-1][j];
    放得下:dp[i][j]=max(dp[i][j],dp[i-1][j-w[i]]+w[i]);
    
  4. 确定初始状态和边界

    dp都为0
    

P1802 5 倍经验日

这个就是普通01背包板子加上不取的经验,再乘5被就行了

要开long long!!

要开long long!!

要开long long!!

  1. 确定状态:

    dp[i - 1][j]代表上一次的经验
    dp[i][j]代表这一次的经验
    
  2. 确定答案

    和模板一样,只需要输出最后一次的经验值就可以了(要乘5倍)
    
  3. 确定状态转移方程

    放不下:dp[i][j]=dp[i-1][j]+l[i];
    放得下:dp[i][j]=max(dp[i][j],dp[i-1][j-w[i]]+w[i]);
    
  4. 确定初始状态和边界

    dp都为0
    

P2663 越越的组队

这个跟上面的一样,都是01背包的改版。

就是需要到这求,只需要求一般就可以了。

  1. 确定状态:

    dp[i - 1][j]代表上一次的成绩
    dp[i][j]代表这一次的成绩
    
  2. 确定答案

    和模板一样,只需要输出最后一次的经验值就可以了(要乘5倍)
    
  3. 确定状态转移方程

    放不下:dp[i][j] = dp[i - 1][j];
    放得下:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - a[i]] + a[i]);
    
  4. 确定初始状态和边界

    dp全都为0
    

P1510 精卫填海

这道题可以用两种方法来解。

这道题十分杂,像“大乱炖”

方法一:按照最小值问题处理

  1. 确定状态:

    dp[j]=dp[i][j];
    pre[j]=dp[i-1][j];
    
  2. 确定答案

    求出最后一次的最小值,然后判断,小于c就输出Impossible,大于c就输出c-ans
    
  3. 确定状态转移方程

    放不下:dp[i][j] = dp[j] = pre[j];
    放得下:dp[j] = min(pre[j], pre[j - w[i]] + val[i]);
    
  4. 确定初始状态和边界

    都要赋值为最大值,出来[0][0]赋值为0。
    最大边界为v+n的最大范围
    

方法二:按照最大值问题处理

  1. 确定状态:

    dp[j]=dp[i][j];
    pre[j]=dp[i-1][j];
    
  2. 确定答案

    求出每一次的最大值,然后判断是否等于-1,等于就输出Impossible,不等于就输出ans
    
  3. 确定状态转移方程

    放不下:dp[j] = pre[j];
    放得下:dp[j] = max(pre[j], v[i] + pre[j - w[i]]);
    
  4. 确定初始状态和边界

    dp都为0,不需要赋值
    

U524956 宠物小精灵之收服

经典的两个限制条件,求解最大值的问题。

  1. 确定状态:

    dp[j][k]=dp[i][j][k];
    pre[j]=dp[i-1][j][k];
    
  2. 确定答案

    最后一次和最后一个的值相比,然后判断是否等于,等于就输出。
    
  3. 确定状态转移方程

    放不下:dp[j][w] = pre[j][w];
    放得下:dp[j][w] = max(pre[j][w], pre[j - v1[i]][w - v2[i]] + 1);
    
  4. 确定初始状态和边界

    dp不用赋值。
    

最后一题

没写。

posted @ 2025-01-16 21:52  非气盈门  阅读(21)  评论(0)    收藏  举报