hdu 2546 典型01背包

分析:每种菜仅仅可以购买一次,但是低于5元不可消费,求剩余金额的最小值问题。。其实也就是最接近5元(>=5)时, 购买还没有买过的蔡中最大值问题,当然还有一些临界情况

1、当余额充足时,可以随意购买菜,即∑p - max_p +5 <= m  时,re = m - ∑p

2、当余额不充足时,有一种特殊情况,不能消费的情况,即m<5时    re = m;

3、余额不足时,只能购买部分菜,转化成01背包问题,找出最接近最接近5的值,

状态转换方程:

f[0][P] = true;f[0][0..P-1]=false;

f[i][p] = f[i-1][p+pi]     如果i-1个菜后余额p+pi、 第 i 个菜后余额p

具体做法:先对菜价格从小到大排序,从前往后根据最有子结构求出各个菜(价格最大的max除外,因为结果一定会减去max值)余额剩余情况,找到最接近5的金额,减去max值就是最佳答案

 

复制代码
//hdu 2546  典型01背包      288 KB    31 ms    
#include<iostream>
#include<algorithm>
using namespace std;
bool my[1001];//统计余额情况
int main()
{
    int n,c[1001],m;
    while(cin >> n)
    {
              int i,j,k,s,re;
              if(!n)break;
              for(s=0,i=1; i<=n; i++)
              {
                    cin >> c[i];s+=c[i];
              }
              sort(c+1,c+n+1);// 不包括c[n+1] 
              //for(i=1;i<=n;i++)cout << c[i];
              cin >> m;
              if(s-c[n] <= m-5 ) re = m-s;
              else if(m < 5) re = m; 
              else{//01背包 
                   for(i=0; i<=m; i++)my[i]=false;
                   my[m]=true;
                   for(i=1; i<n; i++)
                            for(j=5; j+c[i]<=m; j++)
                            if(my[j+c[i]])my[j]=true;
                   for(i=5;i<=m;i++)
                   if(my[i])break;
                   re = i-c[n];
              }
              cout << re << endl;
    }
    return 0;
}
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值