HDU 2546 饭卡

类型:01背包

策略就是把最大的留起来,剩下的尽量去买到5块钱,最后用最大的买。

留最大不用说。尽量买到5块钱就是一个背包问题。

即 背包容量为m-5

每个物品的容量=价值=菜的价格

 

特殊判断:如果m < 5直接输出就可以

 

证明策略正确性:

假设最后买的不是最大的,设为b.最大的设为a. 其他设为C

有(C+a)这个组合尽量买到5块钱 + b > (C+b)->5块钱  + a

1: C+a <= m-5

则 C+b <=m-5

此时 C+a+b = C+b+a 假设不成立

2: C+a > m-5

则假设Ci + a 是其尽量买到5块钱的最优组合

因为 Ci+b < m-5 (Ci + b 不一定是最优组合, 但是可行组合)

有 Ci+a+b = Ci+b+a 假设不成立

综上,假设不成立

所以,原策略成立。

附代码:

HDU 2546 饭卡
/*************************************************************************
    > File Name:    hdu2546.cpp
    > Author:       Shine
    > Created Time: 2013-05-10 上午 9:36:14
    > QuestionType: 01背包
    > Way: 用01背包 求用除了最大的那个数之外 其他的数所能组成的最接近m-5的数
    > Submit: 2 1WA(m-5 想成 m-4) 1AC
    > Gain: 01背包就是 有一个限制 最后价值尽量大 的某个东西拿或不拿的问题。
    > Experience: 无论如何,想几个简单的测试数据,测试一下再提交。
 ************************************************************************/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define max(a,b) ((a)>(b)?(a):(b))

int w[1010], c[1010], f[1010];

int cmp(const void *elem1, const void *elem2) {
    int *p1 = (int *)elem1;
    int *p2 = (int *)elem2;
    return *p1-*p2;
}

int main() {
    int n;
    while (scanf("%d", &n) && n) {
        int i;
        for (i = 0; i < n; i++) {
            scanf("%d", &c[i]);
            w[i] = c[i];
        }
        int m;
        scanf("%d", &m);

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

        qsort(c, n, sizeof(c[0]), cmp);
        qsort(w, n, sizeof(w[0]), cmp);


        memset(f, 0, sizeof(f));
        for (i = 0; i < n-1; i++) {
            int j;
            for (j = m-5; j >= c[i]; j--) {
                f[j] = max(f[j], f[j-c[i]]+w[i]);
            }
        }
        printf("%d\n", m-(f[m-5]+w[i]));
    }
    return 0;
}

 

 

posted on 2013-05-10 10:10  ShineCheng  阅读(164)  评论(0编辑  收藏  举报

导航