神奇的口袋-题解

一、题目链接

https://www.nowcoder.com/practice/9aaea0b82623466a8b29a9f1a00b5d35?tpId=40&tqId=21390&rp=1&ru=%2Fta%2Fkaoyan&qru=%2Fta%2Fkaoyan%2Fquestion-ranking&tab=answerKey

二、题目分析

算法思路:
动态规划
注解
dp[i][j]:表示从前i个物品中选择,使物品总容积为j,有dp[i][j]种不同的选择物品的方式
分析:
对于物品i,我们有两种处理方式
1、不选物品i,若要物品总容积为j,只能使用前i-1种物品使得物品总容积为j,物品选择方式数目为:dp[i-1][j]
2、选物品i,若要物品总容积为j,由于物品i的容积为a[i],因此前i-1种物品的总容积为j-a[i],物品选择方式数目为:dp[i-1][j-a[i]]
所以动归方程为:dp[i][j]=dp[i-1][j]+dp[i-1][j-a[i]]
优化一下:
由于只研究第i行与第i-1行即可,我们用pre[j],dp[j]分别研究第i行与第i-1行
pre[j]:用前i-1种物品使得物品总容积为j,有pre[j]种不同的选择物品的方式
dp[j]:用前i-1种物品使得物品总容积为j,有dp[j]种不同的选择物品的方式
所以动归方程为:dp[j] = pre[j]+pre[j-a[i]]

#include<iostream>
using namespace std;
int n,a[21],dp[41],pre[41];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    pre[0]=1;  //这行超级重要,是动归的边界 
    for(int i=1;i<=n;i++){
        for(int j=1;j<=40;j++){
            dp[j]=pre[j];
            if(j>=a[i])    dp[j]+=pre[j-a[i]];
        }
        for(int j=1;j<=40;j++)    pre[j]=dp[j];
    }
    cout<<dp[40]<<endl;
} 
posted @ 2021-03-11 21:15  saaas  阅读(206)  评论(0)    收藏  举报