背包问题(C语言)
01背包
問題描述:
有n件物品(是件不是種!),每件物品有自己的重量w[n]和價值v[n];現有一個容量為bag的背包,要在背包容量滿足的條件下將物品們裝入背包,使總價值最大,試問應該怎樣放入?最大值為多少?
基本思路:
該問題中每個物體僅有放入或不放入兩種情況,故稱為01背包問題。
現有二元函數maxvalue(i,wight) 表示在考慮前i件物體的情況下,容量為wight的背包所能達到的最大價值。
考慮是否放入第i個物體:
若不放入,則有maxvalue(i,wight)=maxvalue(i-1,wight) ;
若放入,則有maxvalue(i,wight)= maxvalue(i-1,wight-w[i])+ v[i] 。
故該函數滿足以下遞歸式:
maxvalue(i,wight)=max { maxvalue(i-1, wight) , maxvalue(i-1,wight-w[i])+v[i] }
建立二維數組maxvalue[n+1][wight+1],由動態規劃打表即可求出每個狀態下的maxvalue值,其中maxvalue[n+1][wight+1]的值即為所求。再通過對該值進行遞歸回溯,即可找到滿足該值的物品組成。
下面是代碼
#include <stdio.h>int max(int a, int b) {return a > b ? a : b; }int main() {int n, bag;//n為物體個數,bag為背包容量printf("\n請輸入物體個數和背包容量:\n");scanf("%d %d",&n,&bag);int w[100];//每個物體重量int v[100];//每個物體價值printf("請依次輸入每個物體的重量和價值:\n");for(int i = 1; i <= n; i++){scanf("%d %d", &w[i], &v[i]);}int maxvalue[100][100] = {0};//動態規劃表//制表for (int i = 1; i <= n; i++) {for (int wight = 1; wight <= bag; wight++){if (wight < w[i])maxvalue[i][wight] = maxvalue[i-1][wight];elsemaxvalue[i][wight] = max(maxvalue[i-1][wight], maxvalue[i-1][wight-w[i]] + v[i]);}}//打表printf("w i g h t: ");for(int wight=1; wight <= bag; wight++) printf("%-3d", wight);printf("\n");for(int i = 1; i <= n; i++){printf("w%d,v%-3di=%d ", w[i],v[i], i);for(int wight = 1; wight <= bag; wight++){printf("%-3d", maxvalue[i][wight]);}printf("\n");}printf("\n");//輸出最大值printf("MAX=%d\n", maxvalue[n][bag]);//最大值回溯int judge[100] = {0};int x = n, y = bag;while(x != 0 && y != 0){if(maxvalue[x][y] != maxvalue[x-1][y]){judge[x]++;y-=w[x];x--;}else x--;}//輸出滿足條件的物體for(int i = 1; i <= n; i++){if(judge[i]) printf("NO.%d wight%d value%d\n", i, w[i], v[i]);} }?
?
多重背包
問題描述:
在01背包的基礎上,現在每件物體的數量不再為1,而是各自給定,依然求滿足題意的最大總價值。
基本思路:
很容易想到,我們可以模仿01背包的做法,將n件某種物體分為n個1件同種物體,再01背包一下。這樣就會增加n件物體。為了減少增加的物體個數,我們可以利用二進制優化。
有引理:
n以內的正整數,都可以用1, 2, 4,…, 2(k-1), n-2k+1中任意幾個數之和表示
于是,對于n件某種物體,我們便可以增加k個物體,每個物體的重量和價值分別為原物體的1, 2, 4,…, 2(k-1), n-2k+1倍,這樣便可以模擬該種物體放0~n個的所有情況。
#include <stdio.h> #include <string.h>int max(int a, int b) {return a > b ? a : b; }int main() {int n, bag;scanf("%d %d",&n,&bag); //物體種數,背包容量int w[110], v[110], num[110];//轉化為多重背包int w1[5000];int v1[5000];for(int i = 1; i <= n; i++){scanf("%d %d %d", &w[i], &v[i], &num[i]); //重量,價值,數量}int dp[10000];int index = 0;for(int i = 1;i <= n;i++){int t = num[i], k = 1;while(t - k > 0){t -= k;w1[++index] = k * w[i];v1[index] = k * v[i];}w1[++index] = t * w[i];v1[index] = t * v[i];}memset(dp,0,sizeof(dp));for(int i = 1;i <= index;i++)for(int j = bag;j >= w1[i];j--)dp[j] = max(dp[j],dp[j - w1[i]] + v1[i]);printf("%d\n",dp[bag]); }總結
- 上一篇: java面试题36 已知如下的命令执行
- 下一篇: mybatis学习(38):动态sql-