zoukankan      html  css  js  c++  java
  • 背包九讲之三(多重背包)

    证明如下:

    系数可取值
    1,2,4,..2^(k-1),n[i]-2^k+1, k是使得n[i]-2^k+1>=0的最大整数
    前n项和为2^k-1,那么最后一项为 n[i]-2^k+1
    这些系数之和为n[i],且0--n[i]间的每一个整数均可以用若干个系数的和表示
    证明如下:
    ①先证明区间0..2^k-1, 我们有系数1,2,4...2^(k-1) 即k个数,第k个数的二进制的只有第k位为1
    而区间0..2^k-1为二进制第0位到第k-1位是否取值为1的组合,都可以由上面的系数组合得到
    ②再证明区间2^k..n[i],我们与系数1,2,4,..2^(k-1),n[i]-2^k+1
    那么可以由上面的系数组和得到
    n[i]-0,n[i]-1,n[i]-2,n[i]-3,n[i]-2^k+1,
    那么只要证明n[i]-2^k+1 <2^k,即证明n[i]+1<2^(k+1)
    假设n[i]+1>=2^(k+1)成立,即n[i]-2^(k+1)+1>=0成立,
    与前面要求的k是使得n[i]-2^k+1>=0的最大整数矛盾,所以假设不成立。
    综合①②,0--n[i]区间的每一个整数均可以用若干个系数的和表示

    题目地址:http://poj.org/problem?id=1276

     1 /*
     2 有n件物品和一个容量为v的背包,第i种物品最多有n[i]件可用,
     3 每件费用是c[i],价值是w[i],求解将哪些物品放入背包
     4 使费用总和不超过背包容量且价值总和最大
     5 
     6 for(i=1; i<=n; ++i)
     7 for(j=0; j<=v; ++j)
     8 for(k=0; k*c[i]<=j; ++k)
     9     dp[i][j] = max(dp[i][j],dp[i-1][j-k*c[i]]+k*w[i]);
    10 时间复杂度为O(V*∑n[i]);
    11 另一种思想是二进制优化,时间复杂度为O(V*∑log(n[i]));
    12 详见图片
    13 */
    14 #include <stdio.h>
    15 #include <string.h>
    16 int cash;
    17 int n[11],dk[11];
    18 int dp[1000000];
    19 inline int max(const int &a, const int &b)
    20 {
    21     return a < b ? b : a;
    22 }
    23 void CompletePack(int cost)
    24 {
    25     for(int i=cost; i<=cash; ++i)
    26         dp[i] = max(dp[i],dp[i-cost]+cost);
    27 }
    28 void ZeroOnePack(int cost)
    29 {
    30     for(int i=cash; i>=cost; --i)
    31         dp[i] = max(dp[i],dp[i-cost]+cost);
    32 }
    33 void MultiplePack(int cnt, int cost)
    34 {
    35     if(cnt*cost >=cash)//如果第i种物品的费用总和超过背包容量,那么就是完全背包问题
    36         CompletePack(cost);
    37     else
    38     {
    39         int k = 1;//二进制拆分
    40         while(k<cnt)//判断剩下的数字能不能够拆分为k
    41         {
    42             ZeroOnePack(cost*k);
    43             cnt -=k;
    44             k<<=1;
    45         }
    46         ZeroOnePack(cnt*cost);
    47     }
    48 }
    49 int main()
    50 {
    51     int N,i,k,cnt,j;
    52     while(scanf("%d%d",&cash,&N)!=EOF)
    53     {
    54         memset(dp,0,sizeof(dp));
    55         for(i=1; i<=N; ++i)
    56             scanf("%d%d",&n[i],&dk[i]);
    57         for(i=1; i<=N; ++i)
    58         {
    59             MultiplePack(n[i],dk[i]);
    60         }
    61         printf("%d
    ",dp[cash]);
    62     }
    63     return 0;
    64 }

     O(VN)算法:待学习

  • 相关阅读:
    C#2.0泛型学习--入门篇
    [转自MSDN]如何映射 HRESULT 和异常
    js创建hashtable
    滑雪在日本 之 新泻篇 3
    就算神游 之四:富士山和富士游乐园 2
    就算神游 之四:富士山和富士游乐园 9
    滑雪在日本 之 新泻篇 9
    滑雪在日本 之 新泻篇 14
    就算神游 之四:富士山和富士游乐园 4
    挤地铁的感悟
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4279124.html
Copyright © 2011-2022 走看看