您的位置:首页 > 其它

01背包问题*3

2017-09-02 20:11 323 查看

HDU2546 饭卡

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

 

【分析】要使余额最少,最划算的方法当然是用最后的5元买一个最贵的菜。因此先把这5元留出来,对n-1种菜,m-5元余额做一下01背包,将剩下的钱减去最贵的菜即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 1005
int N,V;
int w[maxn];
int dp[maxn];
int main(){
while(scanf("%d",&N)==1&&N){
for(int i=0;i<N;i++){
scanf("%d",&w[i]);
}
scanf("%d",&V);
memset(dp,0,sizeof(dp));
sort(w,w+N);
if(V<5){
printf("%d\n",V);
continue;
}
for(int i=0;i<N-1;i++){
for(int j=V-5;j>=w[i];j--){
dp[j]=max(dp[j],dp[j-w[i]]+w[i]);
}
}
printf("%d\n",V-dp[V-5]-w[N-1]);
}
return 0;
}

HDU2955 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时,强盗是安全的。问在安全的前提下,抢匪最多能获得多少钱。

【分析】看上去是一个背包容量为P的裸01背包,但要注意这里的Pi是小数,并且题目没有限定精确到第几位(想直接乘100的梦想破灭了),因此需要转化一下,把金额当做“容量”来做。我的做法是求出:获得每一个金额需要付出的最小被抓概率,状态转移方程为:dp[j]=min(dp[j],dp[j-c[i]]+p[i]-dp[j-c[i]]*p[i]);然后从最大金额往下找概率小于P的即可。这题另外一个重要的地方是,这里的概率不是直接相加的关系,抢银行x和y后的被抓概率是x+y-x*y。(此题提示我们所有01背包其实都可以换种思路做)

#include<cstdio>
#include<iostream>
#include<algorithm>
#in
d53e
clude<cstring>
using namespace std;
#define maxn 105
float P,p[maxn],dp[maxn*maxn];
int N,c[maxn],sum;
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%f%d",&P,&N);
sum=0;
for(int i=1;i<=N;i++){
scanf("%d%f",&c[i],&p[i]);
sum+=c[i];
}
for(int i=1;i<=sum;i++){
dp[i]=1.0;
}
dp[0]=0;
sum=0;
for(int i=1;i<=N;i++){
sum+=c[i];
for(int j=sum;j>=c[i];j--){
float x=dp[j-c[i]];
dp[j]=min(dp[j],x+p[i]-x*p[i]);
}
}
for(int i=sum;i>=0;i--){
if(dp[i]<P){
printf("%d\n",i);
break;
}
}
}
return 0;
}


HDU1171 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

【题意】有n种设备,每种设备有m台,每台价值为v。要求将这些设备分为价值最为接近的两组,A组价值需要不比B组低。

【分析】求一下价值的总和然后除以2,这就是B组价值的上限。以这个值为容量做一下01背包,然后用总价值减去求得的价值获得A组价值。要注意的是输入的价值数据是每种一个数据的,要处理成每台一个数据才能做。

【……】其实算一下复杂度的话,达到10^9,纯01背包能过还是很人品的,看了下discuss都说数据弱了,据说正解是:1.母函数,2.多重背包(01背包 + 二进制优化)。然后还有人dfs0ms过了。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 55
#define maxm 105
int dp[maxn*maxn*maxm],m[maxn],v[maxn],val[maxn*maxm],sum,s;
int main(){
int N,k;
while(scanf("%d",&N)&&N>0){
sum=0;
k=1;
for(int i=1;i<=N;i++){
scanf("%d%d",&v[i],&m[i]);
sum+=v[i]*m[i];
for(int j=1;j<=m[i];j++){
val[k]=v[i];
k++;
}
}
s=sum/2;
memset(dp,0,sizeof(dp));
for(int i=1;i<k;i++){
for(int j=s;j>=val[i];j--){
dp[j]=max(dp[j],dp[j-val[i]]+val[i]);
}
}
printf("%d %d\n",sum-dp[s],dp[s]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: