模板题 【整数划分】
两种划分方式
前i个数总和为j
总和为i的j个数
都有边界问题需要处理
一个正整数 n 可以表示成若干个正整数之和,形如:n=n1+n2+…+nk,其中 n1≥n2≥…≥nk,k≥1。
我们将这样的一种表示称为正整数 n 的一种划分。
现在给定一个正整数 n,请你求出 n 共有多少种不同的划分方法。
输入格式
共一行,包含一个整数 n。
输出格式
共一行,包含一个整数,表示总划分数量。
由于答案可能很大,输出结果请对 109+7 取模。
数据范围
1≤n≤1000
输入样例:
5
输出样例:
7
1转化为完全背包问题,求数量
容量为n,n个物品体积分别为1-n
f[i][j] = f[i-1][j] + f[i-1][j-i] + f[i-1][j-2*i] + ... +
1.1 f[i][j] = f[i-1][j]+f[i][j-i]
前i个物品容量为j的方案的集合
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1010, M = 1e9+7;
int n;
int f[N][N];
int main()
{
cin>>n;
for( int i = 0; i <= n; i++ )
f[i][0] = 1;//前i个物品都不选也是一种方案
for( int i = 1; i <= n; i++ )
for( int j = 1; j <= n; j++ ){
f[i][j] = f[i-1][j]%M;
if(j >= i)
f[i][j] = (f[i-1][j]+f[i][j-i])%M;
}
cout<<f[n][n]<<endl;
return 0;
}
1.2 优化到一维
f[j] = f[j]+f[j-i];
#include<bits/stdc++.h>
using namespace std;
const int N = 1010, M = 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])%M;
cout<<f[n]<<endl;
return 0;
}
计数类DP
f[i][j]表示所有总和为i,并且恰好表示成j个数的和的方案的集合
根据方案中最小值有没有1来进行集合划分,分为f[i-1[j-1]和f[i-j][j],
有一个边界问题,当总和为0时表示成0个数的方案也算一种
最后求和即可
#include<bits/stdc++.h>
using namespace std;
const int N = 1010, M = 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])%M;
int res = 0;
for( int i = 1; i <= n; i++ )
res = (res+f[n][i])%M;
cout<<res<<endl;
return 0;
}
本文来自博客园,作者:对影丶成三人,转载请注明原文链接:https://www.cnblogs.com/IntroductionToAlgorithms/p/15367447.html
浙公网安备 33010602011771号