dp--背包

背包问题

01背包

(n)个物品,每个物品都有一个价值和体积,有一个容量为(V)的背包,最大可以得到的价值是多少
每个物品都有两种可能,选与不选

code

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

背包恰好装满

定义(dp[i])表示(i)状态可达,初始化(dp)(0),代表不可达,(dp[0] = 1),代表可达
状态转移方程(dp[i] = max(dp[i],dp[i-a[i]]))

code

for(int i = 1; i <= n; i++) 
{
    for(int j = V; j >= a[i]; j++) 
    {
        dp[j] = max(dp[j],dp[j-a[i]]);
    }
}

完全背包

每个物品可以取任意次,而不是一次,所以我们就不用担心(01)背包的状态覆盖问题
直接从(a[i])遍历到(V)

code

for(int i=1; i<=n; i++)
{
  for(int j=w[i]; j<=m; j++)       //和01背包的唯一区别
  {
      f[j]=max(f[j],f[j-w[i]]+v[i]);
  }
}

多重背包转01背包

多重背包例题
每个物品可以取(c)

二进制优化

我们把(c)次划分成(1,2,4,8...)之类的数,然后进行(01)背包就行了
一定存在某个最优的次数,而划分成二进制一定可以表示成那个数

code

for(int i = 0,a,b,c; i < n; i++)
{
    scanf("%d%d%d",&a,&b,&c);           //价值,重量,数量
    int k = 1;
    while(c-k > 0)
    {
        v[t] = k*a;
        w[t++] = k*b;
        c -= k;
        k *= 2;
    }
    v[t] = c*a;         //把剩下的当成一个物品
    w[t++] = c*b;
}

//01背包
for(int i = 0; i < t; i++)  //t个物品
{
    for(int j = m; j >= w[i]; j--)
    {   
        dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
    }
}

单调队列优化

二维背包

增加一维就好了,dp[i][j][k] //第i个,花费j,时间k
也可以空间优化,优化掉第一维度

参考博客

https://www.cnblogs.com/-guz/p/9866118.html

原文地址:https://www.cnblogs.com/hezongdnf/p/11991339.html