计数类DP——整数划分

//背包:容量是n的背包,n个物品的体积分别是1,2,3……n,恰好装满背包的方案数,每个物品可以用无限次

状态表示:f(i, j)

集合:从1~i中选,体积恰好是j的方案

属性:数量

状态计算:

f(i,j):i选了0,1,2,3……n个: f[i - 1][j], f[i-1][j-i], f(i-2, j - 2i), f(i-1,j-si)

从1~i中选,选了2个i,并且和恰好为j

从1~i-1中选,和为j - 2r

……

f[i][j] = f[i-1][j] + f[i-1][j-i] + f[i-1][j-2i] + …… +f[i-1][j-i*s]

f[i][j-i] =            f[i-1][j-i] + f[i-1][j-2i] +……+ f[i-1][j-i*s]

——> f[j] = f[j] + f[j-i]

#include <iostream>
#include <algorithm>

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

int n, 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;
}

第二种解法:

  所有总和是i,并且可以恰好表示成j个数的和的方案

f(i, j)

方案中最小值是1 : 把最小值1去掉就是f[i-1][j-1]

方案中最小值大于1: 把每个数都减去1:f[i-j, j]

f[i][j] = f[i-1][j-1] + f[i-j,j]

ans = f[n][1] + f[n][2]……f[n][n]

完全背包的状态转移方程是:f[i][j] = f[i-1][j] + f[i][j-i]

#include <iostream>
#include <algorithm>

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

int n, 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 ans = 0;
    for(int i = 1;i <= n;i++)
        ans = (ans + f[n][i]) % mod;
        
    cout<<ans<<endl;
}
原文地址:https://www.cnblogs.com/longxue1991/p/12751450.html