您的位置:首页 > 其它

hdu2546 饭卡_特殊的01背包

2017-03-13 16:27 239 查看


饭卡

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

Total Submission(s): 26783    Accepted Submission(s): 9359


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

 

Source

UESTC 6th Programming Contest Online

分析:要使卡上的余额最少,相当于用有限的金额去买最多的菜(总价值最大)。

题目有一个限制条件,就是“卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)”。

也是就是说,当卡上的金额大于等于5时,可以用5元去买任意价格的菜。

所以要预留5元,用来最后买最贵的菜,这样才能使最后的余额最小。

剩下的问题就是,求剩下的m-5元能买到的最高的价值总量,也就是一个单纯的01背包问题了。

//
// Created by Admin on 2017/3/13.
//

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

int price[1010],dp[1010];
int main(){
int n,m;
while(scanf("%d",&n),n){
for (int i = 0; i < n; ++i) {
scanf("%d",&price[i]);
}
sort(price,price+n);  //排序是为了获得价格最高的菜,用预留的5元来购买
scanf("%d",&m);
if (m < 5){  //如果小于5元,无法购买任何菜,余额不变
printf("%d\n",m);
continue;
}
m-=5;  //求剩下m-5元所能买到的最高价值总量
memset(dp,0, sizeof(dp));
for (int i = 0; i < n-1; ++i) {  //m-5元最多能买n-1个菜,剩下的最贵的菜由预留的5元购买
for (int j = m; j >= price[i]; j--) {  //如果饭卡余额j大于某个菜的价格,可以选择购买或者不购买这个菜;如果小于,则说明买不了这个菜,不执行操作
if(dp[j-price[i]]+price[i]>dp[j])  //"dp[j-price[i]]+price[i]":购买   "dp[j]":不购买
dp[j]=dp[j-price[i]]+price[i];  //如果购买这个菜获得的价值比不购买要大,则选择购买,即dp[j]取两者中的较大值
}
}
printf("%d\n",m+5-price[n-1]-dp[m]);  //输出饭卡所剩余额
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hdu dp 01背包