zoukankan      html  css  js  c++  java
  • POJ 3093 Margaritas on the River Walk

    题目大意:给定一个容量为V(题目里是D)的背包和N(题目里是V)件物品各自的体积,求有多少种方法使得背包再也装不下任何物品。

    思路:既然要使背包装不下任何物品,也就是说这时剩下的物品中体积最小的那一件也不能装入背包,所以就可以枚举剩下的最小体积的这件物品来进行动态规划了。

    定义dp[i]=装满体积为i的背包的方法数,volumn[i]=第i件物品的体积,sum[i]=前i件物品的体积之和。

    现在要枚举剩下的物品中体积最小的那一件了。先将所有物品按体积大小排序。

    首先明确,当第i件物品作为剩下的体积最小的物品时,前i-1件物品就都已经被放到背包里面去了。这时,背包剩余体积为V-sum[i-1];由于不能让第i件物品放入背包中,这时需要的是把体积为V-sum[i-1]-volume[i]+1 ~ V-sum[i-1]放满的方法数,(当然V-sum[i-1]-volume[i]+1可能小于0,要处理一下,k = max(V-sum[i-1]-volume[i]+1,0).)也就是dp数组所对应的那几个数字的和。

    如果从体积小的物品开始枚举,考虑当第i件物品不能放入背包的情况,此时,前i-1件物品就都已经被放到背包里面去了,那么就需要计算第i+1 ~ n件物品占据体积k ~ V-sum[i-1]的方法数,然后再在总方法数上加上dp数组对应的值。那么,第i件物品就被考虑了i-1次,此时的算法复杂度为O(N^2 * V)。

    为了使得每件物品只被放入到背包一次,考虑从体积大的物品开始枚举。当第i件物品不能放入背包中,而前i件物品都放入了背包中,这时,我们把已知的i+1 ~ N件物品占据体积k ~ V-sum[i-1]的方法数加到总的方法数ans上,然后再去取第i件物品做01背包,供考虑下一件物品不能放入背包的情况使用,直到枚举完全部的物品。

    如果你要问我,使用同样的方法来顺序枚举可以不可以,那这个很容易否定。因为在逆序枚举的时候,当第i件物品放不下的时候,第i件物品后的物品都被考虑过了,且第i件物品之后的物品也肯定放不下。而顺序枚举的话,第i件物品之前的物品都被考虑过作为当前放不下的最小物品了,第i件物品放不下不意味着前面被考虑过的i-1件物品放不下,这就违背我们当初的假设了,如果这么做了,还有装进背包的物品的方法就也被考虑进去了。

    下面贴一下用降序(逆序枚举)做的代码:

    View Code
     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 int dp[1010],volume[35],sum[35];
     8 
     9 inline int max(int a,int b)
    10 {
    11     return a > b ? a : b;
    12 }
    13 
    14 int main()
    15 {
    16     int ncase,N,V,num;
    17     scanf("%d",&ncase);
    18     for(num = 1;num <= ncase;num++)
    19     {
    20         scanf("%d%d",&N,&V);
    21         memset(sum,0,sizeof(sum));
    22         memset(dp,0,sizeof(dp));
    23 
    24         dp[0] = 1;
    25 
    26         int i,j,ans = 0;
    27         for(i = 1;i <= N;i++)
    28             scanf("%d",&volume[i]);
    29 
    30         sort(volume + 1,volume + 1 + N);
    31 
    32         for(i = 1;i <= N;i++)
    33             sum[i] = sum[i - 1] + volume[i];
    34 
    35         for(i = N;i >= 1;i--)
    36         {
    37             int k = max(0,V - sum[i - 1] - volume[i] + 1);
    38 
    39             for(j = V - sum[i - 1];j >= k;j--)
    40                 ans += dp[j];
    41 
    42             for(j = V;j >= volume[i];j--)
    43                 dp[j] += dp[j - volume[i]];
    44         }
    45 
    46         if(volume[1] > V)    ans = 0;
    47 
    48         printf("%d %d\n",num,ans);
    49     }
    50     return 0;
    51 }
  • 相关阅读:
    1104 Sum of Number Segments (20 分)(数学问题)
    1092 To Buy or Not to Buy (20 分)(hash散列)
    1082 Read Number in Chinese (25 分)(字符串处理)【背】
    1105 Spiral Matrix (25 分)(模拟)
    初识网络安全及搭建网站(内网)
    HTML5开发者需要了解的技巧和工具汇总(转)
    native+web开发模式之web前端经验分享
    移动平台3G手机网站前端开发布局技巧汇总(转)
    Asp.net 中图片存储数据库以及页面读取显示通用方法详解附源码下载
    使用H3Viewer来查看VS2010的帮助文档
  • 原文地址:https://www.cnblogs.com/zhexipinnong/p/2772498.html
Copyright © 2011-2022 走看看