• 【背包问题】


    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个物品有两种选择,一是装进前面的背包中,二是自己新开一个背包

    后边我就不会了……

  • 相关阅读:
    [转]Oracle DB 处理数据
    [转]Oracle DB 使用子查询来解决查询
    [转]Oracle DB 使用连接显示多个表中的数据
    自然连接(natural join)
    [转]Oracle 11g 新特性 -- SQL Plan Management 示例
    [转]Oracle 11g 新特性 -- SQL Plan Management 说明
    Oracle DB 组函数
    Oracle NULL相关函数
    UI :使用 UIPickerView 来选择数据
    UI: UISwitch 创建及使用开关 定制开关
  • 原文地址:https://www.cnblogs.com/liumengyue/p/5247412.html
Copyright © 2020-2023  润新知