计数DP——整数划分

原题传送门

分析1

根据题意这道题是在求组合,不考虑顺序的

这道题可以转化为一个完全背包问题,背包容量是n,有n种物品,这些物品的权重是1~n,每种物品可以取无限次。这不就是之前做过的完全背包问题吗!

背包问题博客链接

完全背包问题中统计的是总价值的最大值,这道题是计数,我们只需要将原来的状态方程中的取最大值操作更改成累加操作,就可以求出所有的方案数

这道题也可以用类似于完全背包的方式进行优化,详细的过程在背包问题的博客中已经有了(我懒的写了),我们可以用类似的方式将二维的优化成一维的

代码1

#include <bits/stdc++.h>
using namespace std;
const int N=1010,MOD=1e9+7;
int n;
int f[N];
int main()
{
    
    
    cin>>n;
    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]表示总和是i且恰好表示成j个数的和的方案数
对于f[i][j]的状态计算可以将这个状态分成两类
1、方案中最小值是1,f[i-1][j-1]即总和减去1,所需要的数也减少一个
2、方案中最小值大于1,f[i-j][j]即所有所有数都减去1,所需要的数的个数不变

代码2

#include <bits/stdc++.h>
using namespace std;
const int N=1010,MOD=1e9+7;
int n;
int f[N][N];
int main()
{
    
    
    cin>>n;
    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 i=1;i<=n;i++) res=(res+f[n][i])%MOD;
    cout<<res<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46126537/article/details/112993243
今日推荐