整体贪心 + 局部01背包 之 hdu 2546

本文探讨了利用5元作为关键因素优化饭卡余额的方法,通过分类讨论不同情况下的最优策略,实现了在购买菜品时使得卡上余额最少的目标。通过01背包变形算法,进一步细化了解决方案,特别关注了如何在有限预算内最大化消费。
//  [7/16/2014 Sjm]
/*
虽然知道5元是解决关键,但自己没想到将5元单独提出来处理,结果一致wa。。。
01背包变形:
目标:
尽量使卡上的余额最少,也就是说尽可能让花销最大。
 
分析:
购买菜时,只可能出现三种情况 :
1)M < 5 :  直接输出 M ;
2)饭卡金额M >= 所有菜的价格总和sum: 答案即 M-sum;
3)饭卡金额M < 所有菜的价格总和sum :
   5元是可以买最贵的菜的最小花费,再尽可能的花去(M-5)元。
	a.5元直接提出,可以从饭卡金额中减去最贵的菜的价格
	b.用(M-5)元去买非a中所买的菜, 尽可能的多花:
		01背包,使价值和体积看成相等,即在保证容量在(M-5)的范围内,价值取到最大
*/
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 const int MAX = 1005;
 8 int N, M;
 9 int val[MAX], dp[MAX];
10 
11 int Solve() {
12     memset(dp, 0, sizeof(dp));
13     for (int i = 1; i < N; ++i) {
14         for (int j = M - 5; j >= val[i]; --j) {
15             dp[j] = max(dp[j], dp[j - val[i]] + val[i]);
16         }
17     }
18     return dp[M - 5];
19 }
20 
21 int main() {
22     //freopen("input.txt", "r", stdin);
23     //freopen("output.txt", "w", stdout);
24     while (~scanf("%d", &N) && N) {
25         int sum = 0;
26         for (int i = 1; i <= N; ++i) {
27             scanf("%d", &val[i]);
28             sum += val[i];
29         }
30         scanf("%d", &M);
31 
32         if (M < 5) {
33             printf("%d\n", M);
34             continue;
35         }
36 
37         if (sum <= M) {
38             printf("%d\n", (M - sum));
39             continue;
40         }
41 
42         sort(val + 1, val + N + 1);
43         int i = 1;
44         printf("%d\n", M - Solve() - val[N]);
45     }
46     return 0;
47 }

 

转载于:https://www.cnblogs.com/shijianming/p/4140830.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值