HDU_01背包系列

HDU_2602 Bone Collector

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 49986    Accepted Submission(s): 20965

Problem Description

Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …

The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the
maximum of the total value the bone collector can get ?

Input

The first line contain a integer T , the number of cases.

Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third
line contain N integers representing the volume of each bone.

Output

One integer per line representing the maximum of the total value (this number will be less than 231).

Sample Input

1
5 10
1 2 3 4 5
5 4 3 2 1

Sample Output

14

分析:裸01背包。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2602

代码清单:

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

const int maxn = 1000 + 5;

int T;
int N, V;
int value[maxn];
int volume[maxn];
int dp[maxn];

void input() {
	scanf("%d%d", &N, &V);
	for(int i = 0; i < N; ++i) {
		cin >> value[i];
	}
	for(int i = 0; i < N; ++i) {
		cin >> volume[i];
	}
}

void solve() {

	memset(dp, 0, sizeof(dp));
	for(int i = 0; i < N; ++i) {
		for(int j = V; j >= volume[i]; --j) {
			dp[j] = max(dp[j - volume[i]] + value[i], dp[j]);
		}
	}

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

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

HDU_2546 饭卡

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 22098    Accepted Submission(s): 7730

Problem Description

电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。

某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。

Input

多组数据。对于每组数据:

第一行为正整数n,表示菜的数量。n<=1000。

第二行包括n个正整数,表示每种菜的价格。价格不超过50。

第三行包括一个正整数m,表示卡上的余额。m<=1000。

n=0表示数据结束。

Output

对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。

Sample Input

1
50
5
10
1 2 3 2 1 1 2 3 2 1
50
0

Sample Output

-45
32

分析:01背包。涉及贪心策略。首先拿出5元买最贵的菜,那么接下来的背包容量为m-5,物品数量n-1,进行01背包就是了。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2546

代码清单:

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

const int maxn = 1000 + 5;

int n, m;
int value[maxn];
int dp[maxn];

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

void solve() {

	if(m < 5) {
		cout << m << endl;
		return ;
	}

	m -= 5;
	sort(value, value + n);
	memset(dp, 0, sizeof(dp));

	for(int i = 0; i < n - 1; ++i) {
		for(int j = m; j >= value[i]; --j) {
			dp[j] = max(dp[j - value[i]] + value[i], dp[j]);
		}
	}

	cout << m + 5 - dp[m] - value[n - 1] << endl;
}

int main() {
	while(cin >> n && n != 0) {
		input();
		solve();
	}
	return 0;
}

HDU_2955 Robberies

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 20096    Accepted Submission(s): 7443

Problem Description

The aspiring Roy the Robber has seen a lot of American movies, and knows that the bad guys usually gets caught in the end, often because they become too greedy. He has decided to work in the lucrative business of bank robbery only for a short while, before
retiring to a comfortable job at a university.

For a few months now, Roy has been assessing the security of various banks and the amount of cash they hold. He wants to make a calculated risk, and grab as much money as possible.

His mother, Ola, has decided upon a tolerable probability of getting caught. She feels that he is safe enough if the banks he robs together give a probability less than this.

Input

The first line of input gives T, the number of cases. For each scenario, the first line of input gives a floating point number P, the probability Roy needs to be below, and an integer N, the number of banks he has plans for. Then follow N lines, where line
j gives an integer Mj and a floating point number Pj .

Bank j contains Mj millions, and the probability of getting caught from robbing it is Pj .

Output

For each test case, output a line with the maximum number of millions he can expect to get while the probability of getting caught is less than the limit set.

Notes and Constraints

0 < T <= 100

0.0 <= P <= 1.0

0 < N <= 100

0 < Mj <= 100

0.0 <= Pj <= 1.0

A bank goes bankrupt if it is robbed, and you may assume that all probabilities are independent as the police have very low funds.

Sample Input

3
0.04 3
1 0.02
2 0.03
3 0.05
0.06 3
2 0.03
2 0.03
3 0.05
0.10 3
1 0.03
2 0.02
3 0.05

Sample Output

2
4
6

题意:抢匪抢劫银行j的金额是Mj,被抓的概率是Pj。当被抓概率小于P时,认为抢匪是可以逃脱的。那么问题来了,在可逃脱的情况下,抢匪最多能抢多少钱。

分析:01背包。一眼看去是裸01背包,但是数组下标却是浮点数,所以得想办法转化。我们把银行的金额总和当做背包容量,不被抓的概率当做价值,那么转移方程就是:dp[j] = max(dp[j - p[i]] * (1 - m[i]), dp[j])。那么结果也就显而易见了,找到最大的容量V,dp[V] > 1 - P,那么这个V就是结果了。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2955

代码清单:

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

#define EPS 0.000000001

const int maxn = 100 + 5;

int T;
double P;
int N;
int p[maxn];
double m[maxn];
double dp[maxn * maxn];

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

void solve() {

	if(P - 0 < EPS) {
		cout << "0" << endl;
		return ;
	}

	int V = 0;
	for(int i = 0; i < N; ++i) {
		V += p[i];
	}

	dp[0] = 1;
	for(int i = 1; i <= V; ++i) dp[i] = 0;

	for(int i = 0; i < N; ++i) {
		for(int j = V; j >= p[i]; --j) {
			dp[j] = max(dp[j - p[i]] * (1 - m[i]), dp[j]);
		}
	}

	for(int i = V; i >= 0; --i) {
		if(dp[i] - (1 - P) > EPS) {
			cout << i << endl;
			return ;
		}
	}
}

int main() {

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

HDU_1203 I NEED A OFFER!

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 24189    Accepted Submission(s): 9728

Problem Description

Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了。要申请国外的任何大学,你都要交纳一定的申请费用,这可是很惊人的。Speakless没有多少钱,总共只攒了n万美元。他将在m个学校中选择若干的(当然要在他的经济承受范围内)。每个学校都有不同的申请费用a(万美元),并且Speakless估计了他得到这个学校offer的可能性b。不同学校之间是否得到offer不会互相影响。“I NEED A OFFER”,他大叫一声。帮帮这个可怜的人吧,帮助他计算一下,他可以收到至少一份offer的最大概率。(如果Speakless选择了多个学校,得到任意一个学校的offer都可以)。

Input

输入有若干组数据,每组数据的第一行有两个正整数n,m(0<=n<=10000,0<=m<=10000)

后面的m行,每行都有两个数据ai(整型),bi(实型)分别表示第i个学校的申请费用和可能拿到offer的概率。

输入的最后有两个0。

Output

每组数据都对应一个输出,表示Speakless可能得到至少一份offer的最大概率。用百分数表示,精确到小数点后一位。

Sample Input

10 3
4 0.1
4 0.2
5 0.3
0 0

Sample Output

44.0%

Hint

You should use printf("%%") to print a ‘%‘.

分析:01背包。此题跟HDU_2955很像,求可能得到至少一份工作的最大概率,那么可以考虑反面,得不到工作的最小概率。那么就很容易理解了,转移方程:dp[j] = min(dp[j - a[i]] * (1 - b[i]), dp[j])。结果自然而然就是 1 - dp[n]了。注意这里输出百分数,记得转化。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1203

代码清单:

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

const int maxn = 10000 + 5;

int n, m;
int a[maxn];
double b[maxn];
double dp[maxn];

void input() {
	for(int i = 0; i <m; ++i) {
		scanf("%d%lf", &a[i], &b[i]);
	}
}

void solve() {

	dp[0] = 1;
	for(int i = 1; i <= n; ++i) dp[i] = 1;

	for(int i = 0; i < m; ++i) {
		for(int j = n; j >= a[i]; --j) {
			dp[j] = min(dp[j - a[i]] * (1 - b[i]), dp[j]);
			//cout << dp[j] << " ";
		}//cout << endl;
	}

	printf("%.1lf%%\n", (1 - dp[n]) * 100);
}

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

HDU_1171 Big Event in HDU

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 35145    Accepted Submission(s): 12188

Problem Description

Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don‘t know that Computer College had ever been split into Computer College and Software College in 2002.

The splitting is absolutely a big event in HDU! At the same time, it is a trouble thing too. All facilities must go halves. First, all facilities are assessed, and two facilities are thought to be same if they have the same value. It is assumed that there is
N (0<N<1000) kinds of facilities (different value, different kinds).

Input

Input contains multiple test cases. Each test case starts with a number N (0 < N <= 50 -- the total number of different facilities). The next N lines contain an integer V (0<V<=50 --value of facility) and an integer M (0<M<=100 --corresponding number of the
facilities) each. You can assume that all V are different.

A test case starting with a negative integer terminates input and this test case is not to be processed.

Output

For each case, print one line containing two integers A and B which denote the value of Computer College and Software College will get respectively. A and B should be as equal as possible. At the same time, you should guarantee that A is not less than B.

Sample Input

2
10 1
20 1
3
10 1
20 2
30 1
-1

Sample Output

20 10
40 40

题意:把所有电脑分成A,B部分,使得A、B两部分金额尽可能相近,并保证金额 A > B。

分析:01背包。把总价平分一下,较小的一部分当做B背包的容量,那么对B进行01背包即可得到B的最大价值,A的价值也就出来了。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1171

代码清单:

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

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

int N;
int V[maxn];
int M[maxn];
int value[maxn * maxm];
int dp[maxn * maxm];

void input() {
	for(int i = 0; i < N; ++i) {
		scanf("%d%d", &V[i], &M[i]);
	}
}

void solve() {
	int sumV = 0, va = 0;
	for(int i = 0; i < N; ++i) {
		sumV += V[i] * M[i];
		for(int j = 0; j < M[i]; ++j) {
			value[va++] = V[i];
		}
	}

	int minV = sumV / 2;
	memset(dp, 0, sizeof(dp));

	for(int i = 0; i < va; ++i) {
		for(int j = minV; j >= value[i]; --j) {
			dp[j] = max(dp[j - value[i]] + value[i], dp[j]);
		}
	}

	printf("%d %d\n", sumV - dp[minV], dp[minV]);
}

int main() {
	while(scanf("%d", &N) != EOF && N >= 0) {
		input();
		solve();
	}
	return 0;
}

时间: 2024-10-10 11:05:01

HDU_01背包系列的相关文章

2017-8-8 Summer:背包系列+斜率优化

A - 最大报销额(01背包) 现有一笔经费可以报销一定额度的发票.允许报销的发票类型包括买图书(A类).文具(B类).差旅(C类),要求每张发票的总额不得超过1000元,每张发票上,单项物品的价值不得超过600元.现请你编写程序,在给出的一堆发票中找出可以报销的.不超过给定额度的最大报销额. Input 测试输入包含若干测试用例.每个测试用例的第1行包含两个正数 Q 和 N,其中 Q 是给定的报销额度,N(<=30)是发票张数.随后是 N 行输入,每行的格式为: m Type1:price1

经典背包系列问题

背包问题I   试题描述 有一个背包容积为 V 和 n 个物品,并给出每个物品有一个体积.要求从 n 个物品中,任取若干个装入背包内,使背包的剩余空间为最小. 输入 第一行两个正整数 V 和 n,分别表示背包的容积和待装物品的个数:第二行包括 n 个正整数,表示 n 个物品的体积,两两之间有一个空格分隔. 输出 一个数,表示背包中剩余空间的最小值 输入示例 24 68 3 12 7 9 7 输出示例 0 其他说明 数据范围:0<V≤20000,0<n≤30 背包问题II   试题描述 仍然是背

POJ之01背包系列

poj3624 Charm Bracelet 模板题 没有要求填满,所以初始化为0就行 #include<cstdio> #include<iostream> using namespace std; #define N 15010 int n,m,v[N],c[N],f[N]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d",&am

背包系列练习( hdu 2844 Coins &amp;&amp; hdu 2159 &amp;&amp; poj 1170 Shopping Offers &amp;&amp; hdu 3092 Least common multiple &amp;&amp; poj 1015 Jury Compromise)

作为一个oier,以及大学acm党背包是必不可少的一部分.好久没做背包类动规了.久违地练习下-.- dd__engi的背包九讲:http://love-oriented.com/pack/ 鸣谢http://blog.csdn.net/eagle_or_snail/article/details/50987044,这里有大部分比较有趣的dp练手题. hdu 2844 Coins 多重背包 就是一个10w的多重背包,每个物品的cost同时也作为value去做背包,我们求的是每个容量下的价值,所以没

POJ 1787 Charlie&#39;s Change

POJ 1787 Charlie's Change 背包系列 + 路程记录 乍一看.多重背包. 再乍.转化01背包?nonono,每样物品的数量达到了10^4,肯定会T. 再乍.看不出来了.去看大牛的题解吧. 哦——转化成完全背包. 怎么转?一般的完全背包是不限个数的.现在我们每一次枚举物品时记录一下取了多少个然后限制一下不要超过个数就好了. 恩.. 路程记录的话完全背包加一个path记录父亲..然后多重背包加一个num数组在dp的时候直接算一算..具体看代码..完全背包的那版路径记录感觉十分巧

HDU4508 湫湫系列故事——减肥记I 【完全背包】

湫湫系列故事--减肥记I Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 2458    Accepted Submission(s): 1254 Problem Description 对于吃货来说,过年最幸福的事就是吃了,没有之一! 但是对于女生来说,卡路里(热量)是天敌啊! 资深美女湫湫深谙"胖来如山倒,胖去如抽丝"的道

HDU 4508.湫湫系列故事——减肥记I【背包】【算法的优化】【8月13】

湫湫系列故事--减肥记I Problem Description 对于吃货来说,过年最幸福的事就是吃了,没有之一! 但是对于女生来说,卡路里(热量)是天敌啊! 资深美女湫湫深谙"胖来如山倒,胖去如抽丝"的道理,所以她希望你能帮忙制定一个食谱,能使她吃得开心的同时,不会制造太多的天敌. 当然,为了方便你制作食谱,湫湫给了你每日食物清单,上面描述了当天她想吃的每种食物能带给她的幸福程度,以及会增加的卡路里量. Input 输入包含多组测试用例. 每组数据以一个整数n开始,表示每天的食物清单

sdut 2934 人活着系列之平方数 (完全背包变形)

题目链接 分析:完全背包的变形,每一层的d[]数组代表这一层的这个数新加入以后所构成的val的种类. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <cstdlib> 6 #include <algorithm> 7 const int maxn = 500+10; 8 using namespa

湫湫系列故事——减肥记I(杭电4508)(完全背包)

湫湫系列故事--减肥记I Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 2612    Accepted Submission(s): 1345 Problem Description 对于吃货来说,过年最幸福的事就是吃了,没有之一! 但是对于女生来说,卡路里(热量)是天敌啊! 资深美女湫湫深谙"胖来如山倒,胖去如抽丝"的道