二進制思想
問題描述:
假設有1000個蘋果,現在要取n個蘋果,如何取?正常的做法應該是將蘋果一個一個拿出來,直到n個蘋果被取出來。
又假設有1000個蘋果和10只箱子,如何快速的取出n個蘋果呢?可以在每個箱子中放 2^i (i<=0<=n)個蘋果,也就是 1、2、4、8、16、32、64、128、256、489(最后的余數),相當於把十進制的數用二進制來表示,取任意n個蘋果時,只要推出幾只箱子就可以了。
多重背包問題
問題描述:
有N種物品和一個容量為V的背包。第 i 種物品最多有n[i]件可用,每件費用是c[i],價值是w[i]。求解將哪些物品裝入背包可使這些物品的費用總和不超過背包容量,且價值總和最大。
問題分析:
很容易想到可以把該問題轉化成01背包問題來考慮,把每n[i] 中的每個物品都當成一個獨立的物品,而這 n[i] 個物品能夠表示的重量其實用 log n[i]個組合后的物品就能表示。
內層循環代碼如下:
int k, t; k = 1; t = n[i]; while(t > k) { for(j=W; j>=c[i]*k; --j) { f[j] = max(f[j], f[j-c[i]*k] + w[i]*k); } t -= k; k *= 2; } for(j=W; j>=c[i]*t; --j) { f[j] = max(f[j], f[j-c[i]*t] + w[i]*t); }
poj上的1014是一道簡單的多重背包問題。http://poj.org/problem?id=1014
源碼如下:

1 #include <stdio.h> 2 #define max(x, y) ((x)>(y) ? (x) : (y)) 3 int f[80001]; 4 int main() 5 { 6 int c[7]; 7 int i, j; 8 int m = 0; 9 int nHarf = 0; 10 while(scanf("%d %d %d %d %d %d", &c[1], &c[2], &c[3], &c[4], &c[5], &c[6]) ) 11 { 12 if(c[1]==0 && c[2]==0 && c[3]==0 && c[4]==0 && c[5]==0 && c[6]==0) 13 { 14 break; 15 } 16 printf("Collection #%d:\n", ++m); 17 nHarf = c[1]*1 + c[2]*2 + c[3]*3 + c[4]*4 + c[5]*5 + c[6]*6; 18 if(nHarf%2 == 1) 19 { 20 printf("Can't be divided.\n\n"); 21 continue; 22 } 23 else 24 { 25 nHarf /= 2; 26 } 27 for(i=1; i<7; ++i) 28 { 29 if(c[i] == 0) continue; 30 if(c[i]*i > nHarf) 31 { 32 for(j=i; j<=nHarf; ++j) 33 { 34 f[j] = max(f[j], f[j-i] + i); 35 } 36 } 37 else 38 { 39 int k, t; 40 k = 1; 41 t = c[i]; 42 while(t > k) 43 { 44 for(j=nHarf; j>=i*k; --j) 45 { 46 f[j] = max(f[j], f[j-i*k] + i*k); 47 } 48 t -= k; 49 k *= 2; 50 } 51 for(j=nHarf; j>=i*t; --j) 52 { 53 f[j] = max(f[j], f[j-i*t] + i*t); 54 } 55 } 56 } 57 if(f[nHarf] == nHarf) 58 { 59 printf("Can be divided.\n\n"); 60 } 61 else 62 { 63 printf("Can't be divided.\n\n"); 64 } 65 for(i=0; i<=nHarf; ++i) 66 { 67 f[i] = 0; 68 } 69 } 70 return 0; 71 }