hdu 2546 饭卡

饭卡

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7251    Accepted Submission(s): 2458


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
 

这是我做的第一道背包题目 01背包。这道题说 有n种菜,每种菜可以买,可以不买。大于等于5元的时候才可以成交交易。所以我们记住最贵的菜,并多拿出5元来买最贵的菜,假设有m元,这样就剩下了m-5元来尽可能多的在剩下n-1个菜中买菜,这就是赤裸裸的01背包问题了。

要善于思考,善于剖析问题的本质,通过题目 回归到算法的精髓上,切忌为做题而做题。

#include<iostream>
using namespace std;
int p[1010];
int opt[1010];
int ZeroOnePack(int maxi,int money,int n)
{
 memset(opt,0,sizeof(opt));
 int i,j;
 for(i=1;i<=n;i++)
 {
  if(i!=maxi)
  {
   for(j=money;j>=p[i];j--)
   {
    if(opt[j]<opt[j-p[i]]+p[i])
     opt[j]=opt[j-p[i]]+p[i];
   }


  }

 }

 return money-opt[money];

}
int main()
{
 int i,n,m,max,maxi,ans;
 while(cin>>n && n)
 {
  p[0]=0;
  max=0;
  for(i=1;i<=n;i++)
  {
   cin>>p[i];
   if(p[i]>max)
   {
    max=p[i];
    maxi=i;
   }

  }
  cin>>m;
  if(m<5)
   cout<<m<<endl;
  else
  {
  ans=ZeroOnePack(maxi,m-5,n)+5-max;
  cout<<ans<<endl;
  }

 }
 return 0;
}

 

 

 

后来发现有另一种方法,就是递推,先排序,先把代码贴在这里,日后研究、

#include"stdio.h"
#include"string.h"
#include"stdlib.h"
int cost[1011];
int c1[2000],c2[2000];
int cmp(const void *a,const void *b)
{
 return *(int *)a-*(int *)b;
}
int main()
{
 int n,m,limit;
 int i,l;
 int ans;
 while(scanf("%d",&n),n)
 {
  for(i=0;i<n;i++) scanf("%d",&cost[i]);
  qsort(cost,n,sizeof(cost[0]),cmp);
  scanf("%d",&m);

  if(m<5) {printf("%d\n",m);continue;}

  limit=m-5;
  memset(c1,0,sizeof(c1));
  memset(c2,0,sizeof(c2));
  for(i=0;i<n;i++)
  {
   for(l=0;l<=limit;l++) if(c1[l]) c2[l+cost[i]]=1;
   c2[cost[i]]=1;
   for(l=0;l<=1100;l++) c1[l]=c2[l];
  }

  ans=0;
  for(i=0;i<=1100;i++) if(c2[i]) ans=i;
  printf("%d\n",m-ans);
 }
 return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值