OI中坑点总结(持续更新)

以下是我个人OI生涯中遇到的坑点的一个小总结,可能是我太菜了,总是掉坑里,请大佬勿喷

1,多重背包的转移顺序

//默认每个物品体积为一(不想打码……)
//dp[i]表示占用背包容量i所能获得的最大价值
for(int i=1;i<=n;i++)
    for(int j=sum;j>0;j--)        //sum表示背包最大容量
        for(int k=0;k<=num;k++)    //num表示这个物品的数量,k表示选取当前物品k件
            if(j>=k)
                dp[j]=min(dp[j],dp[j-k]+value);

简单的多重背包模板,对于学过的人,大概清晰易懂吧

//dp[i]表示占用背包容量i所能获得的最大价值
for(int i=1;i<=n;i++)
    for(int k=0;k<=num;k++)    //num表示这个物品的数量,k表示选取当前物品k件
        for(int j=sum;j>k;j--)        //sum表示背包最大容量
            dp[j]=min(dp[j],dp[j-k]+value);

很相似的代码,只是改了转移顺序,但是为什么会错呢?

类比01背包的倒序转移,

考虑对于某种物品,标程中先枚举 j ,再枚举 k ,这样对于每个位置 j ,只能先于位置 j - i ,由 j - i ( i ∈ [ 0 , k ] )转移一次

而错误写法中,对于位置 j ,可以由转移过的位置 j - i 转移而来

这为什么会导致错误呢?考虑在 j 之前, j - i 已经由 j - i1 - i2 转移而来,多重背包的物品是可以组合的,所以以上的转移等价于 dp[ j - i1 - i2 ] 直接转移到 dp[ i ] ,而我们不能保证 i1 + i2 <= num ,即可能会取多于物品总数的物品

举个例子:

物品数量为7,我们枚举位置13,由8转移而来,而在此之前,位置8由4转移而来,等价于位置13由位置4转移而来,13-4=9>7,转移非法

猜你喜欢

转载自www.cnblogs.com/ivanovcraft/p/9496574.html