zoukankan      html  css  js  c++  java
  • 背包问题详解

    Nyoj289苹果(01背包)

    时间限制:3000 ms  |  内存限制:65535 KB

    难度:3

    描述

    ctest有n个苹果,要将它放入容量为v的背包。给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值。

    输入

    有多组测试数据,每组测试数据第一行为2个正整数,分别代表苹果的个数n和背包的容量v,n、v同时为0时结束测试,此时不输出。接下来的n行,每行2个正整数,用空格隔开,分别代表苹果的大小c和价钱w。所有输入数字的范围大于等于0,小于等于1000。

    输出

    对每组测试数据输出一个整数,代表能放入背包的苹果的总价值。

    样例输入

    3 3

    1 1

    2 1

    3 1

    0 0

    样例输出

    2

    #include<stdio.h>

    #include<string.h>

    #define N 1001

    int dp[N];

    int max(int a,int b)

    {

             if(a>b)

             return a;

             else

             return b;

    }

    int main()

    {

             int n,v,i,j,c,w;

             while(scanf("%d %d",&n,&v))

             {

                       if(n==0&&v==0)

                       break;

                       memset(dp,0,sizeof(dp));

                       for(i=1;i<=n;i++)

                       {

                                scanf("%d %d",&c,&w);

                                for(j=v;j>=c;j--)

                                dp[j]=max(dp[j],dp[j-c]+w);

                       }

                       printf("%d ",dp[v]);

             }

             return 0;

    }

    又见01背包

    时间限制:1000 ms  |  内存限制:65535 KB

    难度:3

    描述

        有n个重量和价值分别为wi 和 vi 的 物品,从这些物品中选择总重量不超过 W 

    的物品,求所有挑选方案中物品价值总和的最大值。

      1 <= n <=100

      1 <= wi <= 10^7

      1 <= vi <= 100

      1 <= W <= 10^9

    输入

    多组测试数据。
    每组测试数据第一行输入,n 和 W ,接下来有n行,每行输入两个数,代表第i个物品的wi 和 vi。

    输出

    满足题意的最大价值,每组测试数据占一行。

    样例输入

    4 5
    2 3
    1 2
    3 4
    2 2

    样例输出

    7

    这道题其实和一般的01背包没有什么区别,只是这道题目按照正常的思维去做不行了,因为容量太大,开个10^9的数组开不了,所以这时候就需要换种思维,这个题刚开始没理解,后来在网上在题解,发现都说是互换重量和价值,但是一直没理解什么意思,后来,仔细想了想那个最最基础的01背包是怎么推出来的才想通了, 也不能说是互换价值和重量,那样其实并不能加深理解,做完这个题之后,发现又对背包理解深了一点,写个博客,留下纪念

    这道题很容易发现其实重量很大,达到10^9,但是价值很小啊,现在就来推一下这个所谓的“互换”是怎么来的 (其实我觉得还不如从最原始的来,不叫做“互换”好理解点), 最原始的那个式子

    dp[i][j]表示当取 i 个, 重量为 j 的时候背包的最大价值,状态转移方程就是 dp[i][j] = max(dp[i - 1][j], dp[i-1][j - weight[i]] + value[i]), 这个式子的意思想必大家都明白吧,前面的那个意思是不取当前这个,后面的这个是取上当前这个物品, 后来再经空间优化之后变成了dp[j] = max(dp[j], dp[j - weight[i]] + value[i]), 仔细观察会发现二维数组时,那两种状态都是i - 1,所以就可以去掉,但是得注意,循环遍历的时候要逆序,正序的话就成完全背包了, 忘了说这个dp[j]表示什么了, dp[j]就是 当取到重量为j 的时候的最大价值。弄明白了这些。这时候就可以来看这个题了, 题目要求和普通的01背包一样,求能装的最大价值,普通方法就是直接找最大价值,现在要换种思维,找最小的重量, 因为同样价值,重量越小,那么最后能装的价值就可能越大,所以这个dp[i][j]就表示 当 取 i 个, 价值为j 的时候的最小重量,状态转移方程为 dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - value[i]] + weight[i]), 和那个最初推的一样,不再罗嗦,空间优化之后状态转移方程为dp[j] = min(dp[j], dp[j - value[i]] + weight[i]), 同样的意思,dp[j]表示 价值为j 的时候的最小重量,到最后只要从最大价值往下遍历这个dp数组,只要找到dp[j] <= 背包重量的时候就直接输出 j , 这时候j就是最大的。

    #include<stdio.h>

    #include<string.h>

    #define Min(a,b) a<b?a:b

    #define N 10003

    int dp[N];

    int weight[102];

    int value[102];

    int main()

    {

             int n,w;

             while(~scanf("%d %d",&n,&w))

             {

                       int sum=0;

                       for(int i=0;i<n;i++)

                       {

                                scanf("%d%d",&weight[i],&value[i]);

                                sum+=value[i];

                       }

                       memset(dp,111,sizeof(dp));

                       dp[0]=0;

                       for(int i=0;i<n;i++)

                       {

                                for(int j=sum;j>=value[i];j--)

                                         dp[j]=Min(dp[j],dp[j-value[i]]+weight[i]);

                       }

                       for(int i=sum;i>=0;i--)

                       if(dp[i]<=w)

                       {

                                printf("%d ",i);

                                break;

                       }

             }

             return 0;

    }

    Nyoj311完全背包

    时间限制:3000 ms  |  内存限制:65535 KB

    难度:4

    描述

    直接说题意,完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是c,价值是w。求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。本题要求是背包恰好装满背包时,求出最大价值总和是多少。如果不能恰好装满背包,输出NO

    输入

    第一行: N 表示有多少组测试数据(N<7)。 
    接下来每组测试数据的第一行有两个整数M,V。 M表示物品种类的数目,V表示背包的总容量。(0<M<=2000,0<V<=50000)
    接下来的M行每行有两个整数c,w分别表示每种物品的重量和价值(0<c<100000,0<w<100000)

    输出

    对应每组测试数据输出结果(如果能恰好装满背包,输出装满背包时背包内物品的最大价值总和。 如果不能恰好装满背包,输出NO)

    样例输入

    2

    1 5

    2 2

    2 5

    2 2

    5 1

    样例输出

    NO

    1

    #include<stdio.h>

    #include<string.h>

    int d[50001];

    int main()

    {

             int n,i,j;

             int c,v,a,b;

             scanf("%d",&n);

             while(n--)

             {

                       scanf("%d%d",&c,&v);

                       memset(d,-11,sizeof(d));

                       d[0]=0;

                       for(i=0;i<c;i++)

                       {

                                scanf("%d%d",&a,&b);

                                for(j=a;j<=v;j++)

                                {

                                         if(d[j]<d[j-a]+b)

                                         d[j]=d[j-a]+b;

                                }       

                       }

                       if(d[v]<0)

                                printf("NO ");

                       else

                                printf("%d ",d[v]);

             }

             return 0;

    }

  • 相关阅读:
    CSS选择符-----关系选择符
    CSS选择符-----元素选择符
    jQuery效果--show([speed,[easing],[fn]])和hide([speed,[easing],[fn]])
    大型网站架构系列:电商网站架构案例
    大型网站架构系列:负载均衡详解(上)
    JBOSS集群和安装
    webwork或Struts配置网站根路径的默认页面办法
    SQL Server 删除重复记录,只保留一条记录
    删除JBOSS eap4.3下的jmx-console、web-console、ws-console、status服务
    SLF4J versions 1.4.0 and later requires log4j 1.2.12 or later 终极解决
  • 原文地址:https://www.cnblogs.com/yinyitianya/p/5425115.html
Copyright © 2011-2022 走看看