背包DP(待编)

背包DP

0/1背包

\(n\)件物品,第i件物品的重量为\(w[i]\),价值为\(v[i]\),有一个承重上限为\(t\)的包,在不超出承重的情况下,装的物品价值总和最大为多少?

代码

for (int i=1; i<=n; i++)
{
    for (int j=1; j<=t; j++)
	{
    	if (w[i] <=j) f[i][j] =max(f[i-1][j], f[i-1][j-w[i]] +v[i]);
 		else if[i][j] =f[i-1][j];
	}
}

滚动数组优化

	for(int i=1;i<=m;i++) 
    {
        for(int j=t;j>=0;j--)
        {
        	dp[j]=max(dp[j-w[i]]+v[i], dp[j]);
        }
    }    

倒着枚举是因为要保证前面的值没有被修改

完全背包

每种物品有无限个

代码

	for(int i=1;i<=m;i++) 
    {
        for(int j=1; j<=t; j++)
        {
        	dp[j]=max(dp[j-w[i]]+v[i], dp[j]);
        }
    }

分组背包

有一些物品,把物品分为\(n\)组,第i组第k个物品的信息为\(w [i] [k]\)\(v [i] [k]\)每组最多选一个物品。对于第i组物品,可以不选,也可以选其中一个,把选每一种的结果求最值。

代码

for (inti=1; i<=n; i++) 
{
    for (intj=C; j>=1; j++) 
    {
        for (intk=1; k<=cnt[i]; k++)
            if (w[i][k] <=j) 
                f[j] =max(f[j], f[j-w[i][k]] +v[i][k]);   
    }
}

多重背包

同0/1背包,每种物品有\(cnt[i]\)个。

思路

根据二进制原理,每个数都能拆成2的幂次之和,我们将每个数都拆成二进制。

分组时,用个\(\log_2(cnt[i])\)数就可以组出选\(0\)~$ cnt[i]$个的全部情况,复杂度降到

\[O(\sum{}\log_2cnt[i]) \]

具体的拆分方案,不能全部拆成二的幂次,先拆除来一些,最后再补一个小于或等于最大倍数的余数,这样可以保证拆除的数的和不会超过\(cnt[i]\)。比如拆分\(25\)

正确的拆法:\(1,2,4,8,10\),可以证明它们能组出0 ~ 25的全部情况

代码鸽着

混合背包

就是多重背包,0/1背包,完全背包混合起来,有的只能取一次,有的能取无限次,有的只能取\(k\)次。

只需把前面几个背包混合就行

例题:例题:樱花

posted @ 2026-05-30 11:16  HEGVDV  阅读(11)  评论(0)    收藏  举报