01背包

Posted bxd123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了01背包相关的知识,希望对你有一定的参考价值。

 

1

初始化的细节问题

我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。

如果是第一种问法,要求恰好装满背包,那么在初始化时除了f[0]为0其它f[1..V]均设为-∞,这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解。

如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。

为什么呢?可以这样理解:初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。

 

2.

多重背包可以分成n个  也可以用二进制来优化:

技术图片
#include <bits/stdc++.h>
 
using namespace std;
 
struct E
{
    int w;  //体积
    int v;  //重量
} lis[2001];
 
int dp[101];
 
int main()
{
    int T,n,m;
    int p,h,k;
    int i,j;
    int index,c;
    scanf("%d%d",&n,&m);                //n表示容量,m表示种类
    index = 0;  //拆分后物品总数
    for( i=1; i<=m; i++)
    {
        c = 1;
        scanf("%d%d%d",&p,&h,&k);       //p表示价格,h表示重量,k表示大米袋数。
        while( k-c>0)
        {
            k -= c;
            lis[++index].w = c*p;
            lis[index].v = c*h;
            c *= 2;
        }
        lis[++index].w = p*k;  //补充不足指数的差值
        lis[index].v = h*k;
    }
    for( i=0; i<=n; i++) dp[i]=0;
    for( i=1; i<=index; i++)   //对拆分后的物品进行0-1背包
    {
        for( j=n; j>=lis[i].w; j--)
            dp[j] = max( dp[j],dp[j-lis[i].w]+lis[i].v);
    }
        printf("%d
",dp[n]);
    return 0;
}
View Code

 

3.

打印物品:

技术图片
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[10005];
bool path[105][10005];
int c[10005],w[10005];
int main()
{
    int N,V;
    while (cin>>V>>N)
    {
        memset(path,0,sizeof(path));
        memset(dp,0,sizeof(dp));
        for (int i = 1;i <= N;++i) cin>>c[i]>>w[i];
        for (int i = N;i >= 1;--i)
        {
            for (int j = V;j >= c[i];--j)
            {
                if (dp[j] < dp[j-c[i]]+w[i])
                {
                    dp[j] = dp[j-c[i]]+w[i];
                    path[i][j] = 1;
                }
            }
        }
        cout<<dp[V]<<endl;
        puts("-----------------------------------------");
        for (int i = 1,j = V;i <= N&&j > 0;i++)
        {
            if (path[i][j])
            {
                printf("%d ",i);
                j -= c[i];
            }
        }
        puts("");
    }
    return 0;
}
View Code

 

 

 

大牛总结的非常好:

https://www.kancloud.cn/kancloud/pack/70133

 

以上是关于01背包的主要内容,如果未能解决你的问题,请参考以下文章

01背包问题模板代码

代码随想录算法训练营第四十二天 | 01背包问题,你该了解这些01背包问题,你该了解这些 滚动数组 416. 分割等和子集

把01背包问题的底裤扒个底朝天!!!

0-1背包问题的回溯法中,剪枝用的上界函数问题

用回溯法求01背包问题,怎样使用C++模板啊,迫切求指点!

01背包模板全然背包 and 多重背包(模板)