N
电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于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
这一题如果没有5元的特殊情况,就是典型的01背包类型。但是存在这一特殊情况---5元钱可以买任何东西。所以要把钱分成两部分,sum-5与5。五元情况下,既然可以都买所以当然买最贵的菜了,然后剩下的菜以sum-5为容量求最大值,即使买不满钱也满足条件。然后分别把卡的钱数与买菜的钱数相减,求和。
void solve(){
input();
if(price<5){cout<<price<<endl;return ;}
memset(dp,0,sizeof(dp));
for(int i=1;i<=n-1;i++)
for(int j=price-5;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+w[i]);
cout<<price-dp[price-5]-w[n]<<endl;
}
R
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
题意:Roy要去抢银行,每抢银行都会有一定的被逮捕的风险m,也会获得一定的钱数。求在低于风险Pi的情况下能获得最大钱数。
首先做这一题的时候,我还没反应过来这是概率问题,将概率累加了,然后就全想错了。Roy抢第i家银行的前提是他抢了i-1银行后还未被逮捕。被逮捕的概率=1-没被逮捕的概率=1-(1-m1)(1-m2)……(1-mn) 这题没有说明容量的最大值,所以以银行的总钱数和为背包容量的最大值。01背包dp[j]=max(dp[j-money[i]]*(1-m[i]),dp[j]);最后倒序找出(1-dp[j]<=pi)输出(注意一个也不抢也是一种可能)
int n;
input1(n);
while(n--){
clear(dp,0);
dp[0]=1.0;
double rate;int o,sum=0;
cin>>rate;input1(o);
fors(o,i){scanf("%d%lf",&bank[i].money,&bank[i].arrest);bank[i].arrest=1-bank[i].arrest;sum+=bank[i].money;}
fors(o,i)
for(int j=sum;j>=bank[i].money;j--)
dp[j]=max(dp[j],dp[j-bank[i].money]*bank[i].arrest);
for(int i=sum;i>=0;i--)if(dp[i]>=1-rate){print(i);break;}
}
W
The title of this problem is familiar,isn’t it?yeah,if you had took
part in the “Rookie Cup” competition,you must have seem this title.If
you haven’t seen it before,it doesn’t matter,I will give you a link:Here is the link: http://acm.hdu.edu.cn/showproblem.php?pid=2602
Today we are not desiring the maximum value of bones,but the K-th
maximum value of the bones.NOTICE that,we considerate two ways that
get the same value of bones are the same.That means,it will be a
strictly decreasing sequence from the 1st maximum , 2nd maximum … to
the K-th maximum.If the total number of different values is less than K,just ouput 0.
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, K(N <= 100 , V <= 1000 , K <= 30)representing the
number of bones and the volume of his bag and the K we need. 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 K-th maximum of the
total value (this number will be less than 2 31). Sample Input 3 5 10
2 1 2 3 4 5 5 4 3 2 1 5 10 12 1 2 3 4 5 5 4 3 2 1 5 10 16 1 2 3 4 5 5
4 3 2 1 Sample Output 12 2 0
题意:有n个骨头和容量为m的背包,每个骨头有不同的价值,通过不同的方法拾取得到不同的总价值(若结果相同视为同一方法),把这些方法得不同到骨头总价值从大到小排序,求第I种方法的价值和。
这题用01背包去做,不过这次不是取最值,而是将能取到的值{dp[j]与dp[j-w[i]]+v[i]}记录下来并去重。最后在dp[V]中找到需要的方法。一开始我便用了set作为数组,记录每个容量的方法结果。但是提交上去要么是Memory-limited要么是Run-time.说明这种法set数组占的内存比较大,这种方法需要优化。在大神的帮助下,我明白了,在01背包基础上实际上数组每次只要筛选并储存I个最大的数据即可。
for(kk=1;kk<=k;kk++)
{
A[kk]=dp[j-vol[i]][kk]+val[i];//A.B都是有序数组
B[kk]=dp[j][kk];
}
A[kk]=-1;
B[kk]=-1;//以负数作为结束的标志同时可以在一数组耗尽时使另一数组正常工作
a=b=c=1;
while(c<=k&&(A[a]!=-1||B[b]!=-1))//检验个数是否到达k或数组是否耗尽
{
if(A[a]>B[b])
{
dp[j][c]=A[a++]; //从大到小排序
}
else
dp[j][c]=B[b++];
if(dp[j][c]!=dp[j][c-1])//去重
c++;
}
X
When the winter holiday comes, a lot of people will have a trip.
Generally, there are a lot of souvenirs to sell, and sometimes the
travelers will buy some ones with pleasure. Not only can they give the
souvenirs to their friends and families as gifts, but also can the
souvenirs leave them good recollections. All in all, the prices of
souvenirs are not very dear, and the souvenirs are also very lovable
and interesting. But the money the people have is under the control.
They can’t buy a lot, but only a few. So after they admire all the
souvenirs, they decide to buy some ones, and they have many
combinations to select, but there are no two ones with the same kind
in any combination. Now there is a blank written by the names and
prices of the souvenirs, as a top coder all around the world, you
should calculate how many selections you have, and any selection owns
the most kinds of different souvenirs. For instance:And you have only 7 RMB, this time you can select any combination with
3 kinds of souvenirs at most, so the selections of 3 kinds of
souvenirs are ABC (6), ABD (7). But if you have 8 RMB, the selections
with the most kinds of souvenirs are ABC (6), ABD (7), ACD (8), and if
you have 10 RMB, there is only one selection with the most kinds of
souvenirs to you: ABCD (10). Input For the first line, there is a T
means the number cases, then T cases follow. In each case, in the
first line there are two integer n and m, n is the number of the
souvenirs and m is the money you have. The second line contains n
integers; each integer describes a kind of souvenir. All the numbers
and results are in the range of 32-signed integer, and 0<=m<=500,
0<n<=30, t<=500, and the prices are all positive integers. There is a
blank line between two cases. Output If you can buy some souvenirs,
you should print the result with the same formation as “You have S
selection(s) to buy with K kind(s) of souvenirs”, where the K means
the most kinds of souvenirs you can buy, and S means the numbers of
the combinations you can buy with the K kinds of souvenirs
combination. But sometimes you can buy nothing, so you must print the
result “Sorry, you can’t buy anything.” Sample Input 2 4 7 1 2 3 44 0 1 2 3 4 Sample Output You have 2 selection(s) to buy with 3
kind(s) of souvenirs. Sorry, you can’t buy anything.
题意:有m钱数和n个不同价格的商品,求一次能买最大商品数,并在这种情况下的购买方法。
这题的基础同样是01背包,求的是最大商品数及购买方法。可以设置两个背包,一个求商品的数量,一个求方法数。求商品数量用01背包。求方法个数在求商品数量上讨论。若dp[j]=dp[j-w[i]]+1;说明这两个方法对应的商品个数相同.方法个数便为两者之和。若dp[j]<dp[j-w[i]]+1;说明出现更大的商品数量,方法个数更新为dp2[j-w[i]];
for(int i = 0; i < n; ++i){
for(int j = m; j >= a[i]; --j){
if(dp1[j] == dp1[j - a[i]] + 1){
dp2[j] = dp2[j] + dp2[j - a[i]];
}
else if(dp1[j]< dp1[j - a[i]] + 1){
dp1[j] = dp1[j - a[i]] + 1;
dp2[j] = dp2[j - a[i]];
}
}
}
总结
训练中遇到不少难做的题,感觉要么是题目理解不到位,要么是没有深入理解背包不能灵活运用,我需要多补题,多总结。