这题wa了一天才ac.......囧
====================================================================
首先主算法是dp无疑,用2进制处理成01背包,貌似还要加上滚动优化,虽然我不懂100*60000的喂马会爆.
wa点1:2进制优化
从上次月赛接触了2进制优化,而到现在我才真正理解.
2进制优化是:假如本来有x个同种物品,可决策的物品数就是x.而2进制处理过后就变成1*val,2*val,4*val.......多种可以同时取的物品,只有lgx个物品了,规模大大减小
例如:取3个就相当于取了val和2*val的物品只有2次决策......按原来的方法有3次决策.
错误的写法:
scanf("%d%d",&x,&val);
while(x)
{
w[k++]=x*;
x/=2;
}
如果某种物品有x个 被处理成价值为x*val, (x/2)*val......的物品,假设容量很大,能全部取走,就相当于取了x+x/2+.......
显然大于原有的物品数,这是个明显的错误T_T......当时我居然忽略了.
正确的写法:
scanf("%d%d",&x,&val)int t;t=1;
while(x-t>0)
{
w[k++]=t*val;
x-=t;
t*=2;
}
w[k++]=x*val;
wa点2:
滚动优化
滚动优化要倒序.....要倒叙要倒序要倒序要倒序........今天第一次注意到,我不知道以前用滚动优化的题目是怎么ac的,测试数据太弱了吧......要不是这道wa还一直不知道
后怕...后怕...后怕
喂马要倒序呢?网上没有搜到权威的说法,写下自己的想法:
先看朴素的dp
for(i=0;i<n;i++)
for(j=w[i];j<m;j++)
{
f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+w[i]);
}
滚动优化后如果第2层循环是
for(j=w[i];j<m;j++)
f[j]=max(f[j],f[j-w[i]]+w[i]);
这样j点被f[j-w[i]]更新后,还会继续更新点j+w[i],但是此时的j与j+w[i]应该是同一层的即f(i,)层的,这样dp的阶段就混乱不堪了.
再看倒序后的
for(j=m-1;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+w[i]);
j点被j-w[i]更新, j-w[i]被比它更小的更新...... 该层的每个点都只被上层的更新过,阶段还是很清晰的......
另外个人觉得直接用dp[2][size]应该也行,dp[0][]存上一阶段的,dp[1][]存当前的,下标t用 t=(t+1)%2轮换就行了......
尝试如此改进,提交后wa一次,不知是不是别的原因.