DP - 完全背包 - 整数划分
本 题 与 — — 本题与—— 本题与——《Pay the Price - UVA - 10313》 类 似 。 类似。 类似。
一个正整数n可以表示成若干个正整数之和,形如:n=n1+n2+…+nk,其中n1≥n2≥…≥nk,k≥1。
我们将这样的一种表示称为正整数n的一种划分。
现在给定一个正整数n,请你求出n共有多少种不同的划分方法。
输入格式
共一行,包含一个整数n。
输出格式
共一行,包含一个整数,表示总划分数量。
由于答案可能很大,输出结果请对109+7取模。
数据范围
1≤n≤1000
输入样例:
5
输出样例:
7
分析:
将 n 分 解 为 n 个 小 于 等 于 n 的 正 整 数 的 和 , 等 价 于 从 小 于 等 于 n 的 n 个 正 整 数 中 选 择 一 些 数 拼 凑 成 n 。 将n分解为n个小于等于n的正整数的和,等价于从小于等于n的n个正整数中选择一些数拼凑成n。 将n分解为n个小于等于n的正整数的和,等价于从小于等于n的n个正整数中选择一些数拼凑成n。
将 小 于 等 于 n 正 整 数 n i 视 作 体 积 为 n i 的 物 品 , n 视 作 背 包 容 量 , 问 题 转 化 为 完 全 背 包 求 方 案 总 数 。 将小于等于n正整数n_i视作体积为n_i的物品,n视作背包容量,问题转化为完全背包求方案总数。 将小于等于n正整数ni视作体积为ni的物品,n视作背包容量,问题转化为完全背包求方案总数。
状 态 表 示 : f [ i ] [ j ] : 考 虑 小 于 等 于 i 的 数 , 求 和 恰 好 为 j 的 方 案 总 数 。 状态表示:f[i][j]:考虑小于等于i的数,求和恰好为j的方案总数。 状态表示:f[i][j]:考虑小于等于i的数,求和恰好为j的方案总数。
状 态 计 算 : ① 、 不 包 含 整 数 i : f [ i ] [ j ] = f [ i − 1 ] [ j ] 。 ② 、 包 含 k 个 整 数 i : f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i − 1 ] [ j − k × i ] , k > = 1 且 j − k × i > = 0 。 状态计算:\\①、不包含整数i:f[i][j]=f[i-1][j]。\\②、包含k个整数i:f[i][j]=f[i-1][j]+f[i-1][j-k×i],k>=1且j-k×i>=0。 状态计算:①、不包含整数i:f[i][j]=f[i−1][j]。②、包含k个整数i:f[i][j]=f[i−1][j]+f[i−1][j−k×i],k>=1且j−k×i>=0。
完 全 背 包 优 化 , 包 含 整 数 i 时 : f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i − 1 ] [ j − i ] + f [ i − 1 ] [ j − 2 × i ] + . . . + f [ i − 1 ] [ j − k × i ] 完全背包优化,包含整数i时:\\f[i][j]=f[i-1][j]+f[i-1][j-i]+f[i-1][j-2×i]+...+f[i-1][j-k×i] 完全背包优化,包含整数i时:f[i][j]=f[i−1][j]+f[i−1][j−i]+f[i−1][j−2×i]+...+f[i−1][j−k×i]
f [ i ] [ j − i ] = f [ i − 1 ] [ j − i ] + f [ i − 1 ] [ j − 2 × i ] + . . . + f [ i − 1 ] [ j − k × i ] f[i][j-i]=\qquad \qquad f[i-1][j-i]+f[i-1][j-2×i]+...+f[i-1][j-k×i] f[i][j−i]=f[i−1][j−i]+f[i−1][j−2×i]+...+f[i−1][j−k×i]
于 是 有 f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i ] [ j − i ] 。 于是有f[i][j]=f[i-1][j]+f[i][j-i]。 于是有f[i][j]=f[i−1][j]+f[i][j−i]。
由 于 包 含 整 数 i 是 从 第 i 层 转 移 过 来 的 , 因 此 优 化 到 一 维 是 从 小 到 大 枚 举 j 。 由于包含整数i是从第i层转移过来的,因此优化到一维是从小到大枚举j。 由于包含整数i是从第i层转移过来的,因此优化到一维是从小到大枚举j。
二维代码:
#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=0;j<=n;j++)
{
f[i][j]=f[i-1][j];
if(j>=i) f[i][j]=(f[i-1][j]+f[i][j-i])%mod;
}
cout<<f[n][n]<<endl;
return 0;
}
一维代码:
#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;
return 0;
}