HDU _2546 01背包问题

本文解析了一道关于食堂饭卡的背包问题,讨论了在特殊规则下如何通过调整背包容量来实现最小余额的目标。介绍了使用动态规划解决此问题的具体步骤,并提供了一个C++实现示例。
A - 饭卡
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit  Status

Description

电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
 

Input

多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。

n=0表示数据结束。
 

Output

对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。
 

Sample Input

1
50
5
10
12 3 2 1 1 2 3 2 1
50
0
 

Sample Output

-45
32
 

 好久没做背包题目了,又有点概念不清了

自己思维还是有点乱,一开始就在纠结这个卡上余额为负值的情况,然后按照常规背包的做法,先把东西塞进去,遇到减出来时负值的情况,则减去最大价值的菜

看上去好像可以,但是会WA

真正的准确思路其实不难想到,在卡上余额大于5的时候,就按常规背包去塞最大化的东西,也就是说,之前就刻意缩小背包容量,使得它为 w-5;这样就能求出卡余额在5元以上的时候,最大的消费额。。。当然,在这之前还要找到最大值得菜,这样,背包之后,再减去最大值的菜。就一定是最余额了。。

其实思路真的很简单,以大于5的卡,做背包,。。剩下的只要减去最大值得菜就行。

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int fruit[1005];
int card[1005];
int max(int x,int y)
{
    if (x>y) return x;
    else
        return y;
}
int main()
{
    int n;
    while (scanf("%d",&n)&&n)
    {
        int i;
        for (i=0; i<n; i++)
            scanf("%d",&fruit[i]);
        int maxn=0;
        int loc;
        for (i=0; i<n; i++)
            if (maxn<fruit[i])
            {
                maxn=fruit[i];
                loc=i;
            }
        int yu;
        scanf("%d",&yu);
        if (yu<5)      //如果初始额度即为小于5,则直接输出
        {
            printf("%d\n",yu);
            continue;
        }
        memset(card,0,sizeof card);
        for (int j=0; j<n; j++)
        {
            if (j==loc) continue;
            for (int k=yu-5; k>=0; k--) //一度忘记了,要从最大值开始递减背包,一开始居然从0开始递增背包,这样会出现状态混乱,这样才能保证每次比较的是前一次的状态和当前状态。
            {
                if (k>=fruit[j])
                    card[k]=max(card[k],card[k-fruit[j]]+fruit[j]);
            }
        }
        int ans=yu-card[yu-5]-maxn;
        printf("%d\n",ans);
    }
    return 0;
}

 

 

转载于:https://www.cnblogs.com/kkrisen/p/3229415.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值