第九章 動態規劃-1269:【例9.13】慶功會

1269:【例9.13】慶功會

時間限制: 1000 ms 內存限制: 65536 KB
提交數: 8343 通過數: 4803
【題目描述】
爲了慶賀班級在校運動會上取得全校第一名成績,班主任決定開一場慶功會,爲此撥款購買獎品犒勞運動員。期望撥款金額能購買最大價值的獎品,可以補充他們的精力和體力。

【輸入】
第一行二個數n(n≤500),m(m≤6000),其中n代表希望購買的獎品的種數,m表示撥款金額。

接下來n行,每行3個數,v、w、s,分別表示第I種獎品的價格、價值(價格與價值是不同的概念)和能購買的最大數量(買0件到s件均可),其中v≤100,w≤1000,s≤10。

【輸出】
一行:一個數,表示此次購買能獲得的最大的價值(注意!不是價格)。

【輸入樣例】
5 1000
80 20 4
40 50 9
30 50 7
40 30 6
20 20 1
【輸出樣例】
1040


思路:二進制優化,1~ m可以用這些數的組合構成: 1 2 4 8…2^x (+ 剩餘的數)。1到n以內的數字,能夠通過 n 內的進制數組合得到,比如 9以內的二進制數有 1 2 4 8,可以自己試一下, 3 = 1 + 2 ,5=1 + 4 ,6= 2 + 4,所以,我們可以利用二進制數的拆分求出所有 n 以內的數;拆分的過程:9 - 1 = 8; 8 - 2 = 6; 6 - 4 = 2 ; 2 - 8 < 0; 那麼要求的 9 以內的二進制數就是 1,2, 4,2,這幾個二進制是能夠組成 9以內包括 9 的所有整數,然後通過 w[ i ] 乘以這些二進制數,把他們當作一件物品來做01揹包的處理,當然,如果沒有用二進制拆分的話就用樸素方法來做。二進制優化,簡單來說,就是把一個數字分成 (1 2 4 8…最大數) 這樣下去的類型爲什麼呢? 因爲這些數字可以組成(1~最大數)中的任何一個數我們可以實現組合把這些抽出來變成一個新的產品,不過 重量和價值 有所不同。變成:
一件 v[i]*1 , w[i]*1

一件 v[i]*2 , w[i]*2

一件 v[i]*4 , w[i]*4

一件 v[i]*8 , w[i]*8

#include <iostream>
#include <cstdio>
using namespace std;

#define N 10000
int c[N], w[N], num[N];
int f[N], new_c[N], new_w[N];
int v, m, tot;
int main() {
	scanf("%d%d", &m, &v);
	for(int i = 1; i <= m; i++) scanf("%d%d%d", &c[i], &w[i], &num[i]);
	for(int i = 1; i <= m; i++) {
		for(int j = 1; j <= num[i]; j <<= 1) {//拆成2的整次冪 <<=1 左移表示乘以2
			num[i] -= j;
			new_c[++tot] = c[i] * j;
			new_w[tot] = w[i] * j;
		}
		if(num[i]) {
			new_c[++tot] = c[i] * num[i];
			new_w[tot] = w[i] * num[i];
			num[i] = 0;
		}
	}
	for(int i = 1; i <= tot; i++) 
		for(int j = v; j >= new_c[i]; j--)
			f[j] = max(f[j], f[j-new_c[i]]+new_w[i]);
	printf("%d\n", f[v]);
	return 0;
}

樸素版本

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
const int maxn = 6005;
using namespace std;
int w[maxn],c[maxn],p[maxn],dp[maxn];
int main(){
	int n,m;
	cin >> n >> m;
	for(int i = 1;i <= n;i++)  cin >> w[i] >> c[i] >> p[i];
	
	for(int i = 1;i <= n;i++){
		for(int j = m;j >= 0;j--){
			for(int k = 0;k <= p[i];k++){
				if(j - k * w[i] < 0) break;
			dp[j] = max(dp[j],dp[j - k*w[i]] + k*c[i]); 
			}
		}
	}
	cout << dp[m];
	return 0;
} 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章