1、可看成完全背包问题。
有n个物品,体积分别为1-n。背包体积为n。问共有多少种装法。
状态表示:f[i][j]为前i个物品中装入体积为j的背包中的装法数量。
状态划分:与完全背包问题相同
#include<iostream>
using namespace std;
const int N =1010,mod = 1e9 + 7;
int n,f[N][N];
int main(){
cin >> n;
for(int i = 0;i <= n;i++) f[i][0] = 1;
for(int i = 1;i<= n;i++)
for(int j = 1;j <= n;j++)
{ f[i][j] = f[i-1][j];
if(j >= i)
f[i][j] = max(f[i][j],f[i-1][j] + f[i][j -i]) %mod; //此式为化简后的式子,详
见完全背包问题
}
cout << f[n][n];
}
还可优化为1维。
2、其他算法
状态表示:f[i][j]表示总和为i,总个数为j的划分方法的数量。
状态划分:将f[i][j]表示的集合按最小值是否为1来划分。
最小值为1 此时将此部分集合中每个划分方法中的总和-1。则此部分集合的划分方法总数可表示为f[i-1][j-1](相当于把每种划分方法中的1减掉)
最小值不为1 此时将此部分集合中每个划分方法的每个数字-1。则此部分集合的划分方法总数可表示为f[i-j][j](因为最小值不为1,所以每个数字减去1后总个数仍为j)
综上,f[i][j] = f[i -1][j - 1] + f[i - j][j]
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int n;
int f[N][N];
int main()
{
cin >> n;
f[1][1] = 1;
for (int i = 2; 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;
}
总结:将一个整体划分为若干部分时可联想到背包问题。