整体贪心 + 局部01背包 之 hdu 2546
// [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 }