HDU _2546 01背包问题

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
",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
",ans);
    }
    return 0;
}
 
原文地址:https://www.cnblogs.com/kkrisen/p/3229415.html