题目链接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1333
GG的关心
Time Limit: 1000 MS Memory Limit: 65536 K
Total Submit: 171(50 users) Total Accepted: 51(35 users) Rating: Special Judge: No
Description
电脑买回来后,MM一直用它专心的搞ACM,看着MM专注的样子,GG也是非常开心,但害怕MM劳累过度影响身体,于是GG经常到超市给MM买一些营养品来补充身体能量。GG到超市购物从来都是刷卡的,可是这种卡很诡异,当用它在超市购物的时候,刷卡机会先判断卡上的余额是否低于5元钱。如果低于5元钱则无法购买任何物品,即使那件物品的金额是小于5的也不可以。而如果卡上的金额大于等于5元则可以进行交易,即使交易成功后卡中余额为负数也是可以的。
现在超市有n种物品,每种物品最多只能买一个。已知每种物品的价格和卡上的余额。问最少可使卡上的余额为多少。
Input
输入包含多组数据。对于每一组数据:
第一行有两个正整数n和m,分别代表物品的种类数,以及卡中的余额。
第二行包含n个正整数p1,p2,p3…pn,分别代表每一种物品的价格。
当n为0时表示输入结束
范围:
m, n <= 1000
pi <= 50 (1 <= i <= n)
Output
对于每组输入,输出一个整数并换行,代表卡上可能的最小余额。
Sample Input
1 5
50
10 50
1 2 3 2 1 1 2 3 2 1
0
Sample Output
-45
32
Hint
买东西是一件一件买。
Source
2012 Spring Contest 5 - Binary Search, Greedy, DP
【思路分析】首先判断一下m是不是大于5,如果m小于5的话,直接输出m的值。否则的话,找出这n种菜种价值最大的那一个,然后对剩余的菜进行(m-5)的01背包,直接求出m-5可以买菜花费的最大钱数,然后用总价值减去dp[m-5]-最大的那个菜就是答案了。
【AC代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,p[1005],dp[1005];
int main()
{
while(~scanf("%d",&n))
{
if(n==0)break;
scanf("%d",&m);
int maxn=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&p[i]);
maxn=max(maxn,p[i]);
}
sort(p+1,p+n+1);
if(m<5)
{
printf("%d\n",m);
continue;
}
memset(dp,0,sizeof(dp));
for(int i=1;i<n;i++)
{
for(int j=m-5;j>=p[i];j--)
{
dp[j]=max(dp[j],dp[j-p[i]]+p[i]);
}
}
printf("%d\n",m-dp[m-5]-maxn);
}
return 0;
}