1、饭卡 hdu2546
http://acm.hdu.edu.cn/showproblem.php?pid=2546
//√31ms 01背包的应用,要变形也变的是输出结果,不是背包模板!
/*
theme:有一张饭卡,给定原始余额为m,食堂规定只要余额>=5就可以购买任意价格的菜,及时减掉之后余额为负
,否则无法购买,及时钱够。现给定n种菜的价格,问可以使卡的余额达到最低多少?(多组案例)
input:多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。
n=0表示数据结束。
output:
对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。
*
*
*
*
*
*
solution:因为01背包算的是余额为i的背包能装下的最大物品(价值),所以我们可以
做减法,算出余额为i的卡最多能消费多少钱,再用开始余额减就可以得到最小余额
有一点要注意就是有个5元的限制条件,所以先利用贪心思想,从m元中拿出5元来买最贵的菜,
再用01背包算m-5的最大消费;一个菜
当然,如果m一开始就小于5则直接输出m(的d[m-5]会错!)
*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdlib.h>
#include<cstring>
#include<queue>
using namespace std;
const int Max=1010;
int price[2000];
int dp[2000];
void zeroOneKnapsack(int maxv,int costs,int gains)
{
for(int i=maxv;i>=costs;--i)
dp[i]=max(dp[i],dp[i-costs]+gains);
}
int main()
{
int n;
while(scanf("%d",&n)&&n)
{
memset(dp,0,sizeof(dp));
for(int i=0;i<n;++i)
scanf("%d",&price[i]);
sort(price,price+n);
int m;
scanf("%d",&m);
if(m<5){
printf("%d\n",m);
continue;
}
for(int i=0;i<n-1;++i)
zeroOneKnapsack(m,price[i],price[i]);
printf("%d\n",m-dp[m-5]-price[n-1]);
}
}
/*
1
50
5
10
1 2 3 2 1 1 2 3 2 1
50
1
4
3
0
-45
32
3
*/
此题还可计算一下所有菜价格之和,若<m则输出m-accumulate(price,price+n,0)