HDU_多重背包系列

HDU_2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 24045    Accepted Submission(s): 10161


Problem Description
急!灾区的食物依然短缺!
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。
请问:你用有限的资金最多能采购多少公斤粮食呢?

后记:
人生是一个充满了变数的生命过程,天灾、人祸、病痛是我们生命历程中不可预知的威胁。
月有阴晴圆缺,人有旦夕祸福,未来对于我们而言是一个未知数。那么,我们要做的就应该是珍惜现在,感恩生活——
感谢父母,他们给予我们生命,抚养我们成人;
感谢老师,他们授给我们知识,教我们做人
感谢朋友,他们让我们感受到世界的温暖;
感谢对手,他们令我们不断进取、努力。 
同样,我们也要感谢痛苦与艰辛带给我们的财富~


 

Input
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。
 

Output
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。
 

Sample Input
  
  
1 8 2 2 100 4 4 100 2
 

Sample Output
  
  
400
 
分析:多重背包,二进制优化,可做模板。
代码清单:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 100 + 5;

int C;
int n, m;
int p[maxn];
int h[maxn];
int c[maxn];
int dp[maxn];

void input() {
	
	cin >> n >> m;
	for(int i = 0; i < m; ++i) {
		cin >> p[i] >> h[i] >> c[i];
 	}
}

void solve() {
	
	memset(dp, 0, sizeof(dp));

	for(int i = 0; i < m; ++i) {
		
		if(p[i] * c[i] >= n) {
			
			for(int j = p[i]; j <= n; ++j) {
				dp[j] = max(dp[j - p[i]] + h[i], dp[j]);
			}
		}
		else {

			int k, ki;
			for(k = 0; ((1 << (k + 1)) - 1) < c[i]; ++k) {
				ki = (1 << k);
				for(int j = n; j >= p[i] * ki; --j) {
					dp[j] = max(dp[j - p[i] * ki] + h[i] * ki, dp[j]);
				}
			}
			ki = c[i] - ((1 << k) - 1);
			for(int j = n; j >= p[i] * ki; --j) {
				dp[j] = max(dp[j - p[i] * ki] + h[i] * ki, dp[j]);
			}
		}
	}

	cout << dp[n] << endl;
}

int main() {
	
	cin >> C;
	for(int t = 0; t < C; ++t) {
		input();
		solve();
	}
	return 0;
}

HDU_2844 Coins

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 12164    Accepted Submission(s): 4852


Problem Description
Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibix opened purse and found there were some coins. He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch.

You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins.
 

Input
The input contains several test cases. The first line of each test case contains two integers n(1 ≤ n ≤ 100),m(m ≤ 100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1 ≤ Ai ≤ 100000,1 ≤ Ci ≤ 1000). The last test case is followed by two zeros.
 

Output
For each test case output the answer on a single line.
 

Sample Input
   
   
3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0
 

Sample Output
   
   
8 4
 

题意:给出n个硬币的数量及价值,问在总价值限定为[1, m]的范围内,能够凑成多少种不同的价值。
分析:多重背包。把m当成容量,进行多重背包后,统计[1, m]内的价值有多少种。
代码清单:
#include <set>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 100 + 5;
const int maxm = 100000 + 5;

int n, m;
int A[maxn];
int C[maxn];
int dp[maxm];
set<int>cnt;

void input() {
	
	for(int i = 0; i < n; ++i) {
		scanf("%d", &A[i]);
	}
	for(int i = 0; i < n; ++i) {
		scanf("%d", &C[i]);
	}
}

void solve() {

	memset(dp, 0, sizeof(dp));
	cnt.clear();

	for(int i = 0; i < n; ++i) {
		if(A[i] * C[i] >= m) {
			for(int j = A[i]; j <= m; ++j) {
				dp[j] = max(dp[j - A[i]] + A[i], dp[j]);
			}
		}
		else {
			int ki, k;
			for(k = 0; ((1 << (k + 1)) - 1) < C[i]; ++k) {
				ki = (1 << k);
				for(int j = m; j >= A[i] * ki; --j) {
					dp[j] = max(dp[j - A[i] * ki] + A[i] * ki, dp[j]);
				}
			}
			ki = C[i] - ((1 << k) - 1);
			for(int j = m; j >= A[i] * ki; --j) {
				dp[j] = max(dp[j - A[i] * ki] + A[i] * ki, dp[j]);
			}
		}
	}

	for(int i = 1; i <= m; ++i) {
		if(dp[i]) cnt.insert(dp[i]);
	}
	printf("%d\n", cnt.size());
}

int main() {

	while(scanf("%d%d", &n, &m) != EOF && n + m != 0) {
		input();
		solve();
	}
	return 0;
}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值