HDU 2546 饭卡(带限制的01背包变形)

 

思路:有几个解法,如下

1)先拿出5块买最贵的菜,剩下的菜再进行01背包。如何证明正确性?设最贵的菜价e,次贵的菜价s,设减去5后的余额为x,会不会产生这样的情况,假设用5元买了e,余额最多能买到x-2钱的菜,那么共买到是x-2+e。而如果挑出s,并且有其他菜价组合加上e等于x呢?不知怎么证明。但是能AC,没有实现。

2)将余额-5作为背包容量,进行01背包,dp时记录下每种背包容量中所不包含的最大菜价,这个菜最后用那5元来买。同样,不知道如何证明。

 1 #include <iostream>

 2 #include <stdio.h>

 3 #include <string.h>

 4 #include <algorithm>

 5 using namespace std;

 6 const int N=1005;

 7 int price[N];

 8 int raw[N];

 9 int dp[N];

10 int mon, n;

11 

12 void cal()

13 {

14     sort(price,price+n); //先排序

15     

16     for(int i=0; i<n; i++)

17     {

18         if(mon-5>=price[i])

19             for(int j=mon-5; j>=price[i]; j--)

20             {

21                 if(dp[j-price[i]]+price[i]>dp[j] )

22                 {

23                     dp[j]=dp[j-price[i]]+price[i];

24                     raw[j]=raw[j-price[i]]; //记录最大的菜价

25                 }

26                 else

27                     raw[j]=price[i];

28             }

29         else //为了防止余额连一个都买不上的情况

30             for(int j=mon; j>0; j--)

31                 raw[j]=price[i];

32     }

33     int ans=0;

34     for(int i=1; i<=mon; i++) //扫出所有可能最大的组合

35     {

36         ans=max(dp[i]+raw[i],ans);

37     }

38     cout<<mon-ans<<endl;

39 }

40 

41 

42 int main()

43 {

44     //freopen("input.txt","r",stdin);

45     while(cin>>n,n)

46     {

47         memset(raw, 0, sizeof(raw));

48         memset(dp, 0, sizeof(dp));

49         memset(price, 0, sizeof(price));

50         

51      

52          for(int i=0; i<n; i++)

53              scanf("%d", &price[i]);

54          cin>>mon;

55          if(mon<5)

56          {

57              cout<<mon<<endl;

58              continue;

59          }

60          cal();

61     }

62     return 0;

63 }
AC代码(01背包)

 

你可能感兴趣的:(HDU)