计数类dp,整数划分

在这里插入图片描述
法1:将此问题变为容量为n的完全背包问题,有质量分别为1,2,3,,,n的物品,每个物品有无穷多件,问能装满这个背包的方法有多少种?
任何一种等式都可以看做是背包问题。
f[i][j] 表示的是从1 - i个物品中选物品,体积恰好是j的选择种数
在这里插入图片描述
按照这个思路写出状态转移方程是
在这里插入图片描述
在这里插入图片描述
这里进行了优化,将s次计算变为了一次
在这里插入图片描述
这里为了节约内存空间,将二维转换为1维,这里把第一维选择了几个物品省略掉了。题目要求的是选择任意多个物品,达到指定体积就可以。因此用一维数组时只需从小到大枚举即可。

#include<iostream>

using namespace std;
const int N = 1010, mod = 1e9 + 7;

int f[N];
int n;

int main(){
    
    
    cin >> n;
    //初始化,只有f[0][0] = 1, 其余f[i][0]都为0
    f[0] = 1;
    
    for(int i = 1; i <= n; i++)
        for(int j = i; j <= n ; j++)
        {
    
    
            f[j] = (f[j] + f[j - i] )% mod;
        }
        
    cout << f[n] << endl;
    return 0;
}

法2:
在这里插入图片描述
f[i][j] = f[i - 1][j - 1] + f[i - j][j];
f[i - 1][j - 1] 表示的集合是最小值是1, 因此将最小值1减出去
f[i - j][j] 表示所有值的最小值都大于1,那么将每个值都减去1,就得到了该表达式


#include<iostream>

using namespace std;
const int N = 1010, mod = 1e9 + 7;

int f[N][N];
int n;

int main(){
    
    
    cin >> n;
    //初始化,只有f[0][0] = 1, 其余f[i][0]都为0
    f[0][0] = 1;
    
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= i ; j++)
        {
    
    
            f[i][j] = (f[i - 1][j - 1] + f[i - j][j] )% mod;
        }
        
    int res = 0;
    for(int j = 1; j <= n ;j++){
    
    
        res = (res + f[n][j]) % mod;
    }
    
    cout << res << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44879626/article/details/108178076
今日推荐