背包九讲之三(多重背包)
生活随笔
收集整理的這篇文章主要介紹了
背包九讲之三(多重背包)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
證明如下:
系數可取值
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)算法:待學習
總結
以上是生活随笔為你收集整理的背包九讲之三(多重背包)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为-eNSP模拟器路由器无法正常启动一
- 下一篇: php 合并图片 (将活动背景图片和动态