HDU 2639 Bone Collector II (01背包,第k解)

 

题意:数据是常规的01背包,但是求的不是最大容量限制下的最佳解,而是第k佳解。

思路:有两种解法。

1)网上普遍用的O(V*K*N)的。

2)先用常规01背包的方法求出背包容量限制下能装的最大价值m,再以m为背包容量再进行一次01背包,dp[j]表示当物品的组合价值为j时,它们的体积之和的最小量。那么就求出了所有可能的价值,从1~m都有,但是其中一些是求不出来的,也就是骨头的价值不能组合成这个数字,那么就得过滤掉。

 1 #include <iostream>

 2 #include <cstdio>

 3 #include <cstring>

 4 #include <limits.h>

 5 using namespace std;

 6 int N, V, K, dp[1000000], w[105], v[105];

 7 

 8 void cal()

 9 {

10     for(int i=0; i<N; i++)

11     {

12         for(int j=V; j>=v[i]; j--)

13             dp[j] = max( dp[j], dp[j-v[i]]+w[i] );

14     }

15     if(K==1)

16     {

17         cout<<dp[V]<<endl;

18         return ;

19     }

20     

21     int m=dp[V];

22     int flag=(1<<30)+(1<<29);

23     dp[0]=0;

24     for(int i=1; i<=m; i++)

25         dp[i]=flag;

26     

27     for(int i=0; i<N; i++)

28     {

29         for(int j=m; j>=w[i]; j--)

30         {

31             if(dp[j-w[i]]<flag)

32                 dp[j]=min(dp[j], dp[j-w[i]]+v[i]);

33             

34         }

35     }

36 

37     int cnt=0;

38     for(int i=m; i>0; i--)

39     {

40         if(dp[i]!=flag && dp[i]<=V )

41         {

42             cnt++;

43             if(cnt==K)

44             {

45                 cout<<i<<endl;

46                 return ;

47             }

48         }

49     }

50     cout<<"0"<<endl;

51 }

52 

53 int main()

54 {

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

56     int t;

57     cin>>t;

58     while(t--)

59     {

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

61         cin>>N>>V>>K;

62         for(int i=0; i<N; i++)

63             cin>>w[i];

64         for(int i=0; i<N; i++)

65             cin>>v[i];

66         cal();

67 

68     }

69     return 0;

70 }
AC代码(第2种解法)

 

你可能感兴趣的:(Collector)