Bone Collector II
Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2610 Accepted Submission(s): 1368
Problem Description
The title of this problem is familiar,isn't it?yeah,if you had took part in the "Rookie Cup" competition,you must have seem this title.If you haven't seen it before,it doesn't matter,I will give you a link:
Here is the link: http://acm.hdu.edu.cn/showproblem.php?pid=2602
Today we are not desiring the maximum value of bones,but the K-th maximum value of the bones.NOTICE that,we considerate two ways that get the same value of bones are the same.That means,it will be a strictly decreasing sequence from the 1st maximum , 2nd maximum .. to the K-th maximum.
If the total number of different values is less than K,just ouput 0.
Here is the link: http://acm.hdu.edu.cn/showproblem.php?pid=2602
Today we are not desiring the maximum value of bones,but the K-th maximum value of the bones.NOTICE that,we considerate two ways that get the same value of bones are the same.That means,it will be a strictly decreasing sequence from the 1st maximum , 2nd maximum .. to the K-th maximum.
If the total number of different values is less than K,just ouput 0.
Input
The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, K(N <= 100 , V <= 1000 , K <= 30)representing the number of bones and the volume of his bag and the K we need. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
Followed by T cases , each case three lines , the first line contain two integer N , V, K(N <= 100 , V <= 1000 , K <= 30)representing the number of bones and the volume of his bag and the K we need. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
Output
One integer per line representing the K-th maximum of the total value (this number will be less than 2
31).
Sample Input
3 5 10 2 1 2 3 4 5 5 4 3 2 1 5 10 12 1 2 3 4 5 5 4 3 2 1 5 10 16 1 2 3 4 5 5 4 3 2 1
Sample Output
12 2 0
题解:这道题是之前我们做过的 Bone Collector的升级版。求前k大的结果。所以我们需要注意不属于最优结果的答案,也可能包含在前k内。解题思路依然是DP。
对于第k个最优解,如果我们考虑每快骨头01,那么我们会有2^1000种结果,必定会爆。所以一定要算法优化。算法是参考学长的,这里主要整理一下对于算法的理解。
算法:申请dp[i][j][k]表示在前i-1个骨头中挑选体积不大于j的前k个解。申请数组a[]储存不添加i的结果,申请b[]储存添加i的结果,最后将两个数组合并取前k个,更新dp。
因为要求前k个,我们就要考虑所有情况,也就是说对于每一块骨头i,我们都要记录在i-1基础上拣或者不拣的情况。为什么每次只取前k个大的呢?这其实是一个放大的思想:在每个阶段i对于任意一个总价值来说都是递增的,而且每个当前总价值在i情况下(挑选第i个骨头时)增大的幅度是一样的(不会出现突然增大很多的情况)。所以我们可以放心的取前k个最大的,并且最终结果一定从这k个中得到。算式表达如下:因为 任意 dp[i][j][m](m > k) < dp[i][j][k] 所以 dp[i-1][j][m] (m > k) < dp[i-1][j][k], dp[i-1][j-w[i]][m] + v[i] < dp[i-1][j-w[i]][k] + v[i] 所以只考虑前k大。
附代码:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <algorithm>
#include <vector>
#define MAX_N 110
#define MAX_V 1010
#define MAX_K 40
using namespace std;
int T,N,V,K;
int value[MAX_N];
int v[MAX_N];
int dp[MAX_V][MAX_K];
int a[MAX_K];
int b[MAX_K];
int main()
{
cin>>T;
while( T-- )
{
cin>>N>>V>>K;
memset(dp,0,sizeof(dp));//初始化为0,若不足k个就输出0
for( int i = 0; i < N; i++ )
scanf("%d",&value[i]);
for( int i = 0; i < N; i++ )
scanf("%d",&v[i]);
for( int i = 0; i < N; i++ )
{
for( int j = V; j >= v[i]; j-- )
{
//初始化
memset(a,-1,sizeof(a));
memset(b,-1,sizeof(b));
//保存前k个加或不加的两种情况
for( int t = 0; t < K; t++ )
{
a[t]=dp[j][t];
b[t]=dp[j-v[i]][t]+value[i];
}
//将两个数组合并
int x=0,y=0,z=0;
while( z < K )
{
if( a[x] == -1 && b[y] == -1 )
break;
if( a[x] > b[y] )
dp[j][z]=a[x++];
else
dp[j][z]=b[y++];
//避免相同的两个数加进去两次
if( dp[j][z] != dp[j][z-1] )
z++;
}
}
}
printf("%d\n",dp[V][K-1]);
}
return 0;
}