题解:整数划分问题(DP)
2016-07-31 21:11
211 查看
总时间限制: 200ms 内存限制: 65536kB
描述
将正整数n 表示成一系列正整数之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1 。
正整数n 的这种表示称为正整数n 的划分。
输入
标准的输入包含若干组测试数据。每组测试数据是一行输入数据,包括两个整数N 和 K。
(0 < N <= 50, 0 < K <= N)
输出
对于每组测试数据,输出以下三行数据:
第一行: N划分成K个正整数之和的划分数目
第二行: N划分成若干个正整数之和的划分数目
第三行: N划分成若干个不同正整数之和的划分数目
第四行: N划分成若干个奇正整数之和的划分数目
样例输入
5 2
样例输出
2
7
3
3
若划分的多个整数可以相同
设dp[i][j]为将i划分为不大于j的划分数
(1) 当i < j 时,i不能划分为大于i的数,所以dp[i][j]=dp[i][i];
(2) 当i > j 时,可以根据划分中是否含有j分为两种情况。若划分中含有j,划分方案数为dp[i-j][j];若划分数中不含j,相当于将i划分为不大于j-1的划分数,为dp[i][j-1]。所以当i>j时dp[i][j]=dp[i-j][j]+dp[i][j-1];
(3) 当i=j 时,若划分中含有j只有一种情况,若划分中不含j相当于将i划分为不大于j-1的划分数。此时dp[i][j]=1+dp[i][j-1]。
dp
可以解决问题1,dp
[k]表示将n划分为最大数不超过k的划分数,可以解决问题3。
若划分的正整数必须不同
设dp[i][j]为将i划分为不超过j的不同整数的划分数
(1) 当i < j时,i不能划分为大于i的数,所以dp[i][j]=dp[i][i];
(2) 当i > j时,可以根据划分中是否含有j分为两种情况。若划分中含有j,则其余的划分中最大只能是j-1,方案数为dp[i-j][j-1];若划分中不含j,相当于将i划分为不大于j-1的划分数,为dp[i][j-1]。所以当i>j时dp[i][j]=dp[i-j][j-1]+dp[i][j-1];
(3) 当i=j时,若划分中含有j只有一种情况,若划分中不含j相当于将i划分为不大于j-1的划分数。此时dp[i][j]=1+dp[i][j-1]
dp
表示将n划分为不同整数的划分数,可以解决问题5.
二 将n划分为k个整数的划分数
设dp[i][j]为将i划分为j个整数的划分数。
(1) i < j为不可能出现的情况,dp[i][j]=0;
(2) 若i = j,有一种情况:i可以划分为i个1之和,dp[i][j]=1;
(3) 若i > j,可以根据划分数中是否含有1分为两类:若划分数中含有1,可以使用“截边法”将j个划分分别截去一个1,把问题转化为i-j的j-1个划分数,为dp[i-j][j-1]; 若划分中不包含1,使用“截边法”将j个划分数的最下面一个数截去,将为题转化为求i-j的j个划分数,为dp[i-j][j]。所以i>j时dp[i][j]=dp[i-j][j-1]+dp[i-j][j]。
dp
[k]为将n划分为k个整数的划分数,可解决问题2。
三 将n划分为若干正奇数之和的划分数
设f[i][j]为将i划分为j个奇数之和的划分数,g[i][j]为将i划分为j个偶数之和的划分数。
使用截边法,将g[i][j]的j个划分都去掉1,可以得到f[i-j][j],所以
g[i][j] = f[i-j][j]。
f[i][j]中有包含1的划分方案和不包含1的划分方案。
对于包含1的划分方案,可以将1的划分除去,转化为“将i-1划分为j-1个奇数之和的划分数”,即f[i-1][j-1];对于不包含1的划分方案,可以使用截边法对j个划分每一个都去掉一个1,转化为“将i-j划分为j个偶数之和的划分数”,即g[i-j][j]。
所以f[i][j]=f[i-1][j-1]+g[i-j][j]。
f
[0]+f
[1]+……+f
为将n划分为若干奇数的划分数,为问题4的答案。
继续上代码, 有注释
描述
将正整数n 表示成一系列正整数之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1 。
正整数n 的这种表示称为正整数n 的划分。
输入
标准的输入包含若干组测试数据。每组测试数据是一行输入数据,包括两个整数N 和 K。
(0 < N <= 50, 0 < K <= N)
输出
对于每组测试数据,输出以下三行数据:
第一行: N划分成K个正整数之和的划分数目
第二行: N划分成若干个正整数之和的划分数目
第三行: N划分成若干个不同正整数之和的划分数目
第四行: N划分成若干个奇正整数之和的划分数目
样例输入
5 2
样例输出
2
7
3
3
分析
一 求将n划分为若干正整数之和的划分数若划分的多个整数可以相同
设dp[i][j]为将i划分为不大于j的划分数
(1) 当i < j 时,i不能划分为大于i的数,所以dp[i][j]=dp[i][i];
(2) 当i > j 时,可以根据划分中是否含有j分为两种情况。若划分中含有j,划分方案数为dp[i-j][j];若划分数中不含j,相当于将i划分为不大于j-1的划分数,为dp[i][j-1]。所以当i>j时dp[i][j]=dp[i-j][j]+dp[i][j-1];
(3) 当i=j 时,若划分中含有j只有一种情况,若划分中不含j相当于将i划分为不大于j-1的划分数。此时dp[i][j]=1+dp[i][j-1]。
dp
可以解决问题1,dp
[k]表示将n划分为最大数不超过k的划分数,可以解决问题3。
若划分的正整数必须不同
设dp[i][j]为将i划分为不超过j的不同整数的划分数
(1) 当i < j时,i不能划分为大于i的数,所以dp[i][j]=dp[i][i];
(2) 当i > j时,可以根据划分中是否含有j分为两种情况。若划分中含有j,则其余的划分中最大只能是j-1,方案数为dp[i-j][j-1];若划分中不含j,相当于将i划分为不大于j-1的划分数,为dp[i][j-1]。所以当i>j时dp[i][j]=dp[i-j][j-1]+dp[i][j-1];
(3) 当i=j时,若划分中含有j只有一种情况,若划分中不含j相当于将i划分为不大于j-1的划分数。此时dp[i][j]=1+dp[i][j-1]
dp
表示将n划分为不同整数的划分数,可以解决问题5.
二 将n划分为k个整数的划分数
设dp[i][j]为将i划分为j个整数的划分数。
(1) i < j为不可能出现的情况,dp[i][j]=0;
(2) 若i = j,有一种情况:i可以划分为i个1之和,dp[i][j]=1;
(3) 若i > j,可以根据划分数中是否含有1分为两类:若划分数中含有1,可以使用“截边法”将j个划分分别截去一个1,把问题转化为i-j的j-1个划分数,为dp[i-j][j-1]; 若划分中不包含1,使用“截边法”将j个划分数的最下面一个数截去,将为题转化为求i-j的j个划分数,为dp[i-j][j]。所以i>j时dp[i][j]=dp[i-j][j-1]+dp[i-j][j]。
dp
[k]为将n划分为k个整数的划分数,可解决问题2。
三 将n划分为若干正奇数之和的划分数
设f[i][j]为将i划分为j个奇数之和的划分数,g[i][j]为将i划分为j个偶数之和的划分数。
使用截边法,将g[i][j]的j个划分都去掉1,可以得到f[i-j][j],所以
g[i][j] = f[i-j][j]。
f[i][j]中有包含1的划分方案和不包含1的划分方案。
对于包含1的划分方案,可以将1的划分除去,转化为“将i-1划分为j-1个奇数之和的划分数”,即f[i-1][j-1];对于不包含1的划分方案,可以使用截边法对j个划分每一个都去掉一个1,转化为“将i-j划分为j个偶数之和的划分数”,即g[i-j][j]。
所以f[i][j]=f[i-1][j-1]+g[i-j][j]。
f
[0]+f
[1]+……+f
为将n划分为若干奇数的划分数,为问题4的答案。
继续上代码, 有注释
#include<cstdio> #include<cstring> #include<algorithm> #define maxn 55 using namespace std; int num[maxn][maxn];//i划分为k个正整数之和 int num2[maxn][maxn];//划分成若干个不同的正整数之和 int f[maxn][maxn];//划分成若干个奇正整数之和 int g[maxn][maxn]; void init() { int i, j; for (int i = 1; i < maxn; i++) num[i][0] = num[0][i] = num2[i][0] = num2[0][i] = 0; for (int i = 1; i < maxn; i++) { for(int j = 1; j < maxn; j++) { if (i < j) num[i][j] = 0; else if (i == j) num[i][j] = 1; else// 最小划分结果是1 不含一 num[i][j] = num[i - 1][j - 1] + num[i - j][j]; } } f[0][0] = 1, g[0][0] = 1; for (i = 1; i < maxn; i++) { for (j = 1; j <= i; j++) { g[i][j] = f[i - j][j]; f[i][j] = f[i - 1][j - 1] + g[i - j][j]; } } } long long fun2(int n, int m)//计算将n进行划分, 最大的划分结果不大于m { if (n == 1 || m == 1) return 1; else if (n < m) return fun2(n, n); else if (n == m) return (1 + fun2(n, m - 1)); else return (fun2(n, m - 1) + fun2(n - m, m)); } int fun(int n, int m)//计算将n进行划分, 最大的划分结果小于m { if (n == 1 && m == 1) return 1; else if (m == 1) return 0; else if (n < m) return fun(n, n); else if (n == m) return (1 + fun(n, m - 1)); else return (fun(n, m - 1) + fun(n - m, m - 1)); } int main(void) { init(); int n, m, res; while (scanf("%d %d", &n, &m) != EOF) { printf("%d\n", num [m]); printf("%d\n", fun(n, n)); printf("%lld\n", fun2(n, n)); res = 0; for (int i = 1; i <= n; i++) res += f [i]; printf("%d\n", res); } return 0; }
相关文章推荐
- OpenJudge_P7215 简单的整数划分问题(DP)
- OpenJudge_P7219 复杂的整数划分问题(DP)
- 整数划分问题 【DP】
- 哈理工OJ 2004 整数划分(经典dp问题)
- OJ演练--整数划分(经典DP问题)
- Openjudge7219 复杂的整数划分问题(dp)
- dp整数划分问题——03:复杂的整数划分问题
- dp-整数划分问题(理论分析)
- 复杂的整数划分问题(dp)
- NYOJ 651 Cut the rope(DP, 经典的整数划分问题)
- 百练:简单的整数划分问题(经典dp)
- hoj 整数划分问题 经典dp
- (dp)openjudge 复杂的整数划分问题
- 区间dp 整数划分问题
- dp 计数问题 复杂整数划分 区间dp
- dp-整数划分问题
- dp-整数划分问题(理论分析)
- nyoj 571 整数划分问题(dp)
- 整数划分问题 【经典DP】
- NYOJ 279 队花的烦恼二和NYOJ 176 整数划分(二)【dp问题或递归】