21.5.8 周末总结

背包问题

上周做的是区间dp,时间太紧了,总结没写,而且区间的题也做的敷衍,早忘干净了,就只剩背包了
理解还不是很深刻,先挑着简单的做了

😀 一、01背包(每种一件)

n件物品,容量为v,每件物品有各自的体积和价值;要求总价值和最大;

因为每种物品只有一件,所以这件物品的选择只有放或不放,动态规划问题都是与子问题有关的,按照我们以前的方程就是:
f[i][v]=max(f[i-1][v],f[i-1][v-w[i]]+c[i]); (恰好能放满,即体积是v)
…不放,…放…;
但是事实上物品不能切割,也不一定恰好放满,所以我们每次求得的子问题也不是恰好的,进而我们最终求得的答案并不是f[n][v],而是f[n][0…v]中的最大值,这时候我们如果让f[i][j]=0(即让他有意义,有小值了才会对最后答案没影响),就可以取f[n][v]了;
优化为一维数组:
当是顺序时:f[i][v]是由f[i][v-w[i]]推来的; 但是我们要的f[i][v]是要由f[i-1][v-w[i]]推来的
我们就把他改为逆序:这时候的f[v-w[i]] 就相当于原来的f[i-1][v-w[i]]

①.普通的求价值
状态方程: f[j]=max(f[j],f[j-w[i]]+c[i]);

初始化细节:
恰好装满时:f[0]=0,f[1…v]=-inf;
不必装满时:f[0…v]=0;

发现一个新东西

memset只可以赋值0和-1,其他的都不行
//fill()函数可定义其他值,且支持区间赋值.两种写法
int a[20];
①.fill(a, a+15, 3);
②.fill_n(a,15, 3);

F:买纪念品
问m元最多买到的物品的数量和当前数量的种类
我们的f[]不是用来表示价值了,而是个数,我们再另外开一个数组来保存可选择的种类数,二维的f[][]不行,i表示的时前i个东西的而不是种类数。
这样我们的转移方程有了:f[j]=max(f[j],f[j-a[i]]+1);(不过不能这么用,得转换成if 和 else,因为还要记录咱们的种类数。

C:不简单的01背包:抢劫银行 (概率)(转换思路,即价值和体积换位置
正常思路是将被抓的概率作为限制条件,但是概率是小数,不可以作为下标,第一次写是受了某个题的影响,给它乘了100(但是小数点个数不确定),然后WA了,又是骗人的测试样例。
那我们就换换方法,去看看别人写的。
嗯,把限制条件换成抢到的钱数,然后用f[]记录逃脱的概率,这样f[]的意义就是要抢小于等于sum的钱,需要的最大概率,要完成的这一串任务的概率不是相加,而是相乘,给出的是被抓的概率,所以我们用(1-p);
而我们原本是要限制的概率P,最
后再用一个循环来找出符合条件的即可。

U: Bookshelf
和C类似,也是转换思路,代码也有点相同,但这次不是两个原价值和体积换
这个题特殊的地方在于,答案是比给定的限定条件的值要大,和普通的类型比反过来了。
提前求出所有的总和,然后继续实行套路,就只有结果有所不同而已,答案需要自己变通一下。

V: Piggy-Bank
又是一个特殊题,求装满一定重量的罐子的最小价值,因为价值和重量不一样。

😀 二、完全背包(每种无限件)

与01背包不同的地方在于物品有无限件,所以在考虑当前这件物品的个数时需要多一维数组,f[i][v-w[i]]正是我们需要的子问题,这时候的f[i][v]是由f[i][v-w[i]]推来的,所以用正序顺序循环;

I:dollars(小数)
给出货币的种类,问有多少种组合能组成给出的金额。
特殊:货币有小数也有整数,将小数化为整数(不四舍五入就错误答案)

②.组合数
初始化有所不同,f[0]得是1,然后有符合的就在自身上加。
状态方程: f[j]=f[j]+f[j-a[i]];

😀 三、多重背包(每种的件数有限)

就先写这么多吧,不好好理解就做题,一切都是白费,学的只是皮毛,上了战场一样不会。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值