• C-01背包问题


    【声明】:非常感谢http://blog.sina.com.cn/s/blog_6dcd26b301013810.html,给我带来的帮助。

    看这个图片表示的意思:

    w[i]表示第i件物品的容积 ,p[i]第i件物品的价值。

    c[i][j] 表示 第i件物品装入容积为j 的空间中的最高价值。 其中i是物品编号,j代表当前背包的容积。

    非常重要的状态转移方程:

      C[i][j] = max(C[i-1][j],C[i-1][j-w[i]]+p[i])

    C[i-1][j]表示放第i-1件物品,背包容量为j的总价值。

    C[i-1][j-w[i]]表示存放第i-1件物品,背包容量为  j-w[i] 的总价值;再加上当前第i件物品的价值

    【也就是说在选择是不是要放一件物品时,就看看不放该物件的价值 与 放了该物件的总价值 哪个更大一点的问题。】

    int knapsack(int m,int n)//总容量,物品数量
    {
        int i,j,w[10],p[10];//每件物品的容量个价值
        for(i=1;i<n+1;i++)
        scanf("
    %d,%d",&w[i],&p[i]);
    
        for(i=0;i<10;i++)
            for(j=0;j<100;j++)
                c[i][j]=0;
    
        for(i=1;i<n+1;i++)//数量
            for(j=1;j<m+1;j++)
            {
                if(w[i]<=j){//j表示当前容量,当前容量如果小于该件物品的容量,
                            //也就是该件物品放不进去背包
                     if(p[i]+c[i-1][j-w[i]]>c[i-1][j])
                         c[i][j]=p[i]+c[i-1][j-w[i]];
                     else
                         c[i][j]=c[i-1][j];
                }else
    
                     c[i][j]=c[i-1][j];
             }
         return(c[n][m]);
    }

     01

    由于使用一维数组解01背包会被多次用到,完全背包的一种优化实现方式也是使用一维数组,所以我们有必要理解这种方法。

    如果只使用一维数组f[0…v],我们要达到的效果是:

    第i次循环结束后f[v]中所表示的就是使用二维数组时的f[i][v],即前i个物体面对容量v时的最大价值。

    我们知道f[v]是由两个状态得来的,f[i-1][v]和f[i-1][v-c[i]],使用一维数组时,当第i次循环之前时,f[v]实际上就是f[i-1][v],那么怎么得到第二个子问题(f[i-1][v-c[i]])的值呢?事实上,如果在每次循环中我们以v=V…0的顺序推f[v]时,就能保证f[v-c[i]]存储的是f[i-1][v-c[i]]的状态。状态转移方程为:

    v = V...0; f(v) = max{ f(v), f(v-c[i])+w[i] }

    我们可以与二维数组的状态转移方程对比一下

    f(i,v) = max{ f(i-1,v), f(i-1,v-c[i])+w[i] }

     

    还是看上图:如果按照v=0-V的顺序的话,第一件物品存入包中和上图一样,当存入第二件物品的时候,v= 4时,价值为5。但是没有办法准确知道f[i-1][v-c[i]](即f[v-c[i])。【由于是一维数组,数据会被覆盖】

    但是,如果按照v = V--0的顺序。存入第一件物品的时候,和上图是一样的,此时f[10] = ...=f[5] = 4,开始存放第二件物品的时候,v =V = 10;f(v) = max{ f(v), f(v-c[i])+w[i] }(即f[10] = max{f[10],f[10-c[2]+w[2]} = max{f[10],f[6]+w[2] = max{4,4+5} = 9);v = 9……以此类推就可以得出上图中的第二行。

     【再想不明白,自己按照上图执行一遍即可。】

     程序代码:

    #include<stdio.h>
    #include<stdlib.h>
    #define MAXN 100+10
    
    int f[MAXN];
    int w[MAXN],c[MAXN];
    
    int main()
    {
        int N,V;
        int i=0,j;
        scanf("%d%d",&V,&N);
        for(i = 0;i<N;i++)
        {
            scanf("%d%d",&c[i],&w[i]);
        }
        memset(f,0,sizeof(f));
        for(i = 0;i<N;i++)
            for(j = V;j>=c[i];j--)
            {
               f[j] = f[j]>(f[j-c[i]]+w[i]) ? f[j]: f[j-c[i]]+w[i];
            }
    
        printf("max value si %d
    ",f[V]);
        return 0;
    }

    这样一来就全部解决了问题了………………^__^

  • 相关阅读:
    CF1051D Bicolorings dp
    loj2480 [CEOI2017]One-Way Streets 边双+树上差分
    有趣的支配树
    AtCoder Regular Contest 81
    [BZOJ5305][HAOI2018]苹果树(DP)
    [BZOJ4699]树上的最短路(最短路+线段树)
    [BZOJ3507][CQOI2014]通配符匹配(DP+Hash)
    [Luogu4724][模板]三维凸包(增量构造法)
    [BZOJ5317][JSOI2018]部落战争(闵可夫斯基和)
    [WC2014]时空穿梭(莫比乌斯反演)
  • 原文地址:https://www.cnblogs.com/plxx/p/3575583.html
Copyright © 2020-2023  润新知