4.6 每日一题题解

三角形

涉及知识点:

  • 背包dp

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;
}
posted @ 2020-04-06 08:19  QFNU-ACM  阅读(86)  评论(0编辑  收藏  举报