清华大学机试 整数拆分 需要二刷 *完全背包问题

基本思想:

https://www.nowcoder.com/practice/376537f4609a49d296901db5139639ec?tpId=40&tqId=21339&rp=1&ru=%2Fta%2Fkaoyan&qru=%2Fta%2Fkaoyan%2Fquestion-ranking&tPage=1

第一次见到完全背包问题,并且这个背包问题所描述的并非整体最大值的问题,而是放置次数的问题;

很多案例没有讲出为神马要这么遍历dp数组,这里说一下:

1.首先,对于n个放置元素的确定,采用打表进行;

2.dp[0]=1,是为了边界初始化,来保证dp[1]当放置元素为1时,可以正常进行初始化,值得注意的是,dp数组内放的是当前值的方案个数;

3.对于dp数组初始化,可以直接从1-n进行放置元素举例,但是不同于寻常的放置元素的转换方程,求放与不放的最大值;

而是dp[j]=dp[j]+dp[j-n];

原因在于,当我们决定要放n种元素的时候,就要去寻找之前n占位时,剩余容量能放多少种,也就是dp[j-n]。而由于当我们在枚举第n种元素前,就已经研究过1-n-1种元素在当前容量有放置有几种方案,所以要再加上dp[j];

关键点:

后续在刷题吧,第一次见到这种dp内存储方案数目的dp数组;

01背包问题中也仅仅是直接记录放置情况;

链接:https://www.nowcoder.com/questionTerminal/376537f4609a49d296901db5139639ec?f=discussion
来源:牛客网

#include <iostream>
#include <string>
#include <vector>
#include <map>
 
#include <queue>
#include <stack>
#include <algorithm>
 
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>      //rand ( ), srand ( )
#include <ctime>        //time ( )
using namespace std;
 
int n, dp[1000002], a[21];
 
int main ( )
{
    int i, j, t;
    for ( i = 1; i <= 20; i ++ )
        a[i] = ( 1 << ( i - 1) );
    dp[0] = 1;
    while ( cin >> n )
    {
        memset ( dp + 1, 0, sizeof ( dp ) );
        for ( i = 1; i <= 20; i ++ )
        {
            for ( j = a[i]; j <= n; j ++ )
            {
                dp[j] += dp[j - a[i]];
                dp[j] %= 1000000000;
            }
        }
        cout << dp[n] << endl;
    }
    return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/songlinxuan/p/12388991.html