题解:整数划分问题(DP)
来源:互联网 发布:君子去仁 恶乎成名 编辑:程序博客网 时间:2024/05/21 13:22
总时间限制: 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
分析
一 求将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[n][n]可以解决问题1,dp[n][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][n]表示将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[n][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[n][0]+f[n][1]+……+f[n][n]为将n划分为若干奇数的划分数,为问题4的答案。
继续上代码, 有注释
#include<cstdio>#include<cstring>#include<algorithm>#define maxn 55using 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[n][m]); printf("%d\n", fun(n, n)); printf("%lld\n", fun2(n, n)); res = 0; for (int i = 1; i <= n; i++) res += f[n][i]; printf("%d\n", res); } return 0;}
- 题解:整数划分问题(DP)
- 整数划分问题 【DP】
- 整数划分问题 DP
- dp-整数划分问题
- nyoj 571 整数划分问题(dp)
- dp-整数划分问题(理论分析)
- dp-整数划分问题(理论分析)
- 复杂的整数划分问题(dp)
- 区间dp(整数划分,石子划分)
- nyoj90整数划分(dp)
- 百练:简单的整数划分问题(经典dp)
- 哈理工OJ 2004 整数划分(经典dp问题)
- hoj 整数划分问题 经典dp
- Openjudge7219 复杂的整数划分问题(dp)
- OpenJudge_P7215 简单的整数划分问题(DP)
- OpenJudge_P7219 复杂的整数划分问题(DP)
- 整数划分多种题解
- 划分问题(dp)
- 判断字符串是否为数字&&判断字符串是否为字母&&判断子字符串是否为汉字
- 【javase复习】## day5 异常 ##
- boosting
- static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
- Caffe学习笔记(三)——Matlab接口
- 题解:整数划分问题(DP)
- Java EE笔记一
- BestCoder Round #85 (hdu5776,hdu5777,hdu5776)
- 动态规划--钢条切割问题
- 路由器
- getchar(), cin.get()
- Java EE笔记二
- 帮忙设计的一些UI
- Scrum实战读书笔记