涉及知识点:
solution:
- 背包是dp算法中非常经典的一个问题(如果打算学dp的同学必须要学会背包问题),具体的大家可以看我发在群里的背包九讲pdf
- 关于这道题目,我们可以对每一个宝箱做一个背包
- 题目要求从每一个宝箱中有且只能取一个,所以设dp[i][j]为枚举到第i个宝箱,可以获得钱数等于j的方案数
- 那么转移方程就等于 dp[ i ][ z ] += dp[ i-1 ][ z - a[ i ][ j ] ] ,初始化dp[ 0 ][ 0 ] = 1
- i代表前i个宝箱,z代表可以获得z钱,a[ i ][ j ]代表枚举的第i个宝箱的第j个钱,dp[ i ][ z ]就等于前i个宝箱可以获得z钱的方案数
- j的范围是0~10000,最后从小到达枚举dp[ n ][ j ],代表前n个宝箱中可以获得钱数等于j的方案数,不断和k做差就得到了答案
std:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 105;
int a[maxn][maxn],dp[maxn][maxn*maxn],len[maxn];
int main()
{
int n , k;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>len[i];
for(int j=1;j<=len[i];j++)
cin>>a[i][j];
}
dp[0][0] = 1;
for(int i=1;i<=n;i++){
for(int z=0;z<=10000;z++){
for(int j=1;j<=len[i];j++){
dp[i][z] += dp[i-1][z-a[i][j]];
}
}
}
ll ans = 0;
for(int i=1;i<=10000;i++){
if(dp[n][i] >= k){
ans += 1ll*k*i;
break ;
}else{
ans += 1ll*dp[n][i]*i;
k -= dp[n][i];
}
}
cout<<ans<<endl;
return 0;
}