AC wing . 900 整数划分
一个正整数 n 可以表示成若干个正整数之和,形如:n=n1+n2+…+nk,其中 n1≥n2≥…≥nk,k≥1。
我们将这样的一种表示称为正整数 n 的一种划分。
现在给定一个正整数 n,请你求出 n 共有多少种不同的划分方法。
输入格式
共一行,包含一个整数 n。
输出格式
共一行,包含一个整数,表示总划分数量。
由于答案可能很大,输出结果请对 109+7 取模。
数据范围
1≤n≤1000
输入样例:
5
输出样例:
7
核心思想:
有两种思考手段,第一种是完全背包(有n件物品,他们的数量都是无限的),第二种就是分类进行dp,先看第一种,首先有一个容量为n的背包,有n件物品,分别的体积是i,f[i,j]表示前i个物品总体积正好为j时的方案数,下面有个完全背包的式子需要推一下:
f[i][j] = f[i-1][j] + f[i-1][j-i] + f[i-1][j-2i]+……+f[i-1][j-si]
f[i][j-i] = f[i-1][j-i] + f[i-1][j-2i]+……+f[i-1][j-si]
-> f[i][j] = f[i-1][j] + f[i][j-i]
具体实现看代码
#include<iostream>
using namespace std;
const int N = 1010 , mod = 1e9+7;
int f[N], 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;
}
二、分类进行dp , f[i,j]表示总和为i,分成j个物品的方案数,那么他的状态可以分成有最小值是1的集合和最小值不是1这两个集合,最小值是1的状态转移方程是f[i-1][j-1] , 最小值不是1的状态转移方程是,f[i-j][j] , 映射成每个物品都减去1,这个想法非常之精妙,所以状态转移方程就可以写成:
f[i][j] = f[i-1][j-1] + f[i-j][j]
因为j有很多个,所以说要把每一个j都加起来才是答案
具体看代码:
#include<iostream>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int f[N][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 += f[n][i];
cout << res << endl;
return 0;
}