hduoj 饭卡 java_HDUOJ_2546(饭卡)(背包问题)

HDUOJ_2546(饭卡)(背包问题)

饭卡

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

Total Submission(s): 16658    Accepted Submission(s): 5800

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

提示:(思路摘自:hehe的博客(博客园))(注:本人也是看了这个博客,才明确了做题思路.思路简单易懂,同时也由于本人较懒,所以把思路复制粘贴了过来,并稍作修改)

(1)如果所有的菜的总金额sum小于等于卡上金额,我们可以购买所有的菜,并且直接输出余额。

(2)如果所有的菜,除去最贵的菜,的金额sum-max小于等于value-5,我们可以先购买其他的菜,最终卡上金额必大于等于5,最后购买那道最贵的菜,使总金额最低。同情况(1)可以直接输出余额,可与(1)条件合并。/*在下面的代码中,我没有考虑此种情况,考虑此种情况,可以节约程序运行时间*/

(3)如果卡上金额小于5,什么也买不了,直接输出余额。

(4)如果都不符合,那就进入最复杂的处理了。先购买适量的菜,使卡内余额的金额大于等于且最接近5(即用t去买其它的菜,尽可能花掉较多的钱(<=t), (t=m-5,m为饭卡最初的金额)最后购买最贵的菜(用sort排序找出最贵的菜)。子问题也就是01背包问题。

My  solution:

/*2015.8.26*/

#include

#include

#include

using namespace std;

int num[1100],f[1100];

int main()

{

int n,m,i,j,sum,t,min;

while(scanf("%d",&n)==1&&n)

{

sum=0;

memset(num,0,sizeof(num));

memset(f,0,sizeof(f));

for(i=1;i<=n;i++)

{

scanf("%d",&num[i]);

sum+=num[i];

}

scanf("%d",&m);

if(m<5)

{

printf("%d\n",m);/*金额不足5元时,不能买东西,数值原样输出*/

continue;

}

if(sum+5<=m)/*当所有菜的价钱之和小于卡里余额 m-5时,说明买完所有菜后卡里余额>=5,因此直接输出余额*/

{

printf("%d\n",m-sum);

continue;

}

t=m-5;/*卡里留5元,多余的钱用来买菜*/

sort(num,num+n+1);/*把所有的菜的价格进行排序,最后一个元素的价格是最大的,放在最后买*/

for(i=1;i

for(j=t;j>=num[i];j--)

{

f[j]=max(f[j],f[j-num[i]]+num[i]);

} /*f[t]存放的是在不超出t的情况下,花掉最多的钱数*/

min=m-f[t]-num[n];/*m是最初卡里的余额,f[t]是在余额不低于5的情况下,花掉的最大钱数,num[n]是价格最大的菜(放在最后买)*/

printf("%d\n",min);

}

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值