【背包问题】

01背包

二维这样写

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

因为很长时间没写,受一维的影响,一开始写成了这样

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

需要注意的是,a[i][1~w[i]]没值啊没值啊没值啊(是栋栋发现的!栋栋太厉害了!)

for (int i=1;i<=m;i++)
       {
           for(int j=0;j<w[i];j++)
             a[i][j]=a[i-1][j];
        for (int j=w[i];j<=t;j++)
        a[i][j]=max(a[i-1][j],a[i-1][j-w[i]]+v[i]);
       }
这是栋栋改的,所以我要存下来

一维

j是从m循环到w[i](省去判断了,不用担心上面那个问题)

为什么倒着循环?

省略了第一维,在二维数组中,我们是由a[i-1][j-w[i]]更新a[i][j]的

    a[j]=max(a[j],a[j-w[i]]+v[i]);

推a[j]需要用到a[j-w[i]],显然j-w[i]<j,如果正着循环,就相当于用a[i][j-w[i]]更新a[i][j]了

    for (int i=1;i<=n;i++)
        for (int j=m;j>=w[i];j--)
        a[j]=max(a[j],a[j-w[i]]+v[i]);

 如果要把背包装满呢?

那就把a[0]初始化为0,a[1~n]初始化为-∞。

a[0]相当于装满了容量为0的背包,价值为0,是合法状态。

a[1~n]全是不合法的状态。

在循环过程中,如果a[j-w[i]]是合法的状态,那么a[j]就是合法的状态。

(上面是小敏颜告诉我的)

 而对于普通的背包,全部初始为0,就是全都合法。

 

完全背包

和01背包的区别是一种物品可以放无限次。所以刚才说的倒着循环,就没必要了。

因为既然可以放无限次,就不用考虑上一次到底是放还是没放了。

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

多重背包

n种物品,每种有sum[i]件,价值为v[i],代价w[i],装到容量为m的包里使价值最大

拆成01背包

二进制拆分 

    xp[0]=1;for (int i=1;i<=14;i++) xp[i]=xp[i-1]*2;

这地方注意,xp[0]等于1。

    for (int i=1;i<=n;i++){
        for (int j=0;j<=14;j++){
            if (num[i]<xp[j]) break;
            w[++cnt]=w1[i]*xp[j];    v[cnt]=v1[i]*xp[j];
            num[i]-=xp[j];
        }
        if (num[i]){
            w[++cnt]=w1[i]*num[i];v[cnt]=v1[i]*num[i];
        }
    }

w,v是新的数组,num[]是每个物品的件数,价值和代价要一起拆。

混合背包

就是把三种背包合起来,读入的时候判断一下件数。(完全背包最多是m/w[i])

然后拆。。。01背包做。

二维费用

数组加一维,循环加一重

像这样(我懒)(下边是个01背包,别的拆一拆。。。)

    for (int i=1;i<=n;i++)
        for (int j=zl;j>=w[i];j--)
            for(int k=tj;k>=v[i];k--)
            a[j][k]=max(a[j][k],a[j-w[i]][k-v[i]]+V[i]);

分组背包

for 所有的组k
    for v=V..0
        for 所有的i属于组k
            f[v]=max(f[v],f[v-c[i]]+w[i])

特别注意一下2、3重循环的顺序。这样才能保证每组内的物品只装一次。

 

多个背包问题(我也不知道叫啥)

有多个相同的背包,每个背包容量相同,向里边装入n个物品,求最大数量

用f[j][k] 表示装到第j个背包,第j个背包已经装了k个容量的最大数量。

对于第i个物品有两种选择,一是装进前面的背包中,二是自己新开一个背包

后边我就不会了……

posted @ 2016-03-06 14:36  mengyue  阅读(174)  评论(0编辑  收藏  举报