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; }