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

posted @ 2020-02-08 19:23  hezongdnf  阅读(132)  评论(0编辑  收藏  举报