nyoj 571 整数划分问题(dp)

╰+哭是因爲堅強的太久メ 2022-03-20 01:38 319阅读 0赞

整数划分(三)

时间限制: 1000 ms | 内存限制: 65535 KB

难度: 3

描述

整数划分是一个经典的问题。请写一个程序,完成以下要求。

输入

每组输入是两个整数n和k。(1 <= n <= 50, 1 <= k <= n)

输出

对于输入的 n,k;
第一行: 将n划分成若干正整数之和的划分数。
第二行: 将n划分成k个正整数之和的划分数。
第三行: 将n划分成最大数不超过k的划分数。
第四行: 将n划分成若干个 奇正整数之和的划分数。
第五行: 将n划分成若干不同整数之和的划分数。
第六行: 打印一个空行

样例输入

  1. 5 2

样例输出

  1. 7
  2. 2
  3. 3
  4. 3
  5. 3

提示

样例输出提示:
1.将5划分成若干正整数之和的划分为: 5, 4+1, 3+2, 3+1+1, 2+2+1, 2+1+1+1, 1+1+1+1+1
2.将5划分成2个正整数之和的划分为: 3+2, 4+1
3.将5划分成最大数不超过2的划分为: 1+1+1+1+1, 1+1+1+2, 1+2+2
4.将5划分成若干 奇正整数之和的划分为: 5, 1+1+3, 1+1+1+1+1
5.将5划分成若干不同整数之和的划分为: 5, 1+4, 2+3

来源

HOJ

整数划分问题是一个数学上的很经典的问题,这几天学习了一下、、、发现这道题是最全面的一道整数划分题,nyoj中有四道是关于整数划分的题,题号分别是:90、176、651、571、也就是做出来这道题、这个问题也就解决了、、、、下面是我一个博客中看到的整数划分问题最全面的讲解、附地址:

http://www.programfan.com/acm/show.asp?qid=57\#comment

http://www.cnblogs.com/xiaoxian1369/archive/2011/09/12/2174212.html

代码:

  1. /*对于输入的 n,k;
  2. 第一行: 将n划分成若干正整数之和的划分数。
  3. 第二行: 将n划分成k个正整数之和的划分数。
  4. 第三行: 将n划分成最大数不超过k的划分数。
  5. 第四行: 将n划分成若干个 奇正整数之和的划分数。
  6. 第五行: 将n划分成若干不同整数之和的划分数。
  7. 第六行: 打印一个空行*/
  8. #include<iostream>
  9. #include <cstring>
  10. #include<vector>
  11. #include <cstdio>
  12. using namespace std;
  13. #define N 55+1
  14. int dp[N][N];
  15. int main()
  16. {
  17. //分为若干个正整数和
  18. //memset(dp,0,sizeof(dp));
  19. int n,k;
  20. int out[6];
  21. while(cin>>n>>k)
  22. {
  23. memset(dp,0,sizeof(dp));
  24. //任意个正整数和,则dp[i][j]表示i分解成最大不超过j的个数,
  25. //分为最大是j和最大不是j,则dp[i][j]=dp[i-j][j]+dp[i][j-1];
  26. dp[0][0]=1;
  27. for (int i=0;i<=n;i++)
  28. {
  29. for (int j=1;j<=n;j++)
  30. {
  31. if(j<=i)
  32. dp[i][j]=dp[i-j][j]+dp[i][j-1];
  33. else
  34. dp[i][j]=dp[i][i];
  35. }
  36. }
  37. out[1]=dp[n][n];
  38. out[3]=dp[n][k];
  39. //分成K个正整数的和 ,分为k个数中没有1,和有1,
  40. //dp[i][j],将i划分为j个dp[i][j]=dp[i-j][j]+dp[i-1][j-1];
  41. memset(dp,0,sizeof(dp));
  42. for(int i=1;i<=n;i++)
  43. for (int j=1;j<=i;j++)
  44. {
  45. if(j==1)
  46. dp[i][j]=1;
  47. else
  48. dp[i][j]=dp[i-j][j]+dp[i-1][j-1];
  49. }
  50. out[2]=dp[n][k];
  51. //奇数和dp[i][j]为划分最大的奇数不超过j的数,
  52. //则dp[i][j]=dp[i-n(j)][j]+dp[i][j-2];n(j)为不超过j的最大奇数
  53. //初始条件,dp[i][1]=1,j为偶数时候dp[i][j]=dp[i][j-1];当i==n(j) ,
  54. //出现dp[0][j],也就是当i为奇数时候,dp[0][j]=1;
  55. memset(dp,0,sizeof(dp));
  56. for(int i=0;i<=n;i++)
  57. {
  58. dp[i][1]=1;
  59. if(i&1)
  60. dp[0][i]=1;
  61. }
  62. for (int i=1;i<=n;i++)
  63. {
  64. for (int j=1;j<=n;j++)
  65. {
  66. if(j&1)
  67. {
  68. if(j<=i)
  69. dp[i][j]=dp[i-j][j]+dp[i][j-1];
  70. else
  71. dp[i][j]=dp[i][i];
  72. }
  73. else
  74. dp[i][j]=dp[i][j-1];
  75. }
  76. }
  77. out[4]=dp[n][n];
  78. //不同正整数和,dp[i][j]是不超过j的不同的整数和,dp[i][j]=dp[i-j][j-1]+dp[i][j-1];初始状态dp[1][1]=1;
  79. //当i==j时,出现dp[0][j-1],表示先拿出一个j出来,这时候就应该是1中情况。
  80. memset(dp,0,sizeof(dp));
  81. dp[0][0]=1;
  82. for (int i=0;i<=n;i++)
  83. {
  84. for (int j=1;j<=n;j++)
  85. {
  86. if(j<=i)
  87. dp[i][j]=dp[i-j][j-1]+dp[i][j-1];
  88. else
  89. dp[i][j]=dp[i][i];
  90. }
  91. }
  92. out[5]=dp[n][n];
  93. for (int i=1;i<=5;i++)
  94. {
  95. cout<<out[i]<<endl;
  96. }
  97. cout<<endl;
  98. }
  99. }

发表评论

表情:
评论列表 (有 0 条评论,319人围观)

还没有评论,来说两句吧...

相关阅读

    相关 整数划分问题

    根据n和m的关系,考虑以下几种情况:         (1)当 n = 1 时,不论m的值为多少(m > 0 ),只有一种划分即 \{ 1 \};         (...

    相关 整数划分问题

    题目描述 计算将一个给定的正整数划分为一系列正整数的和的方案数,称为整数的划分问题,例如,当给定正整数为6时,可以有如下划分: 6=6; 6=5+1; 6=4+2=4+

    相关 整数划分 区间dp

    题目链接[点击打开链接][Link 1] 题目大意是说有一个不超过二十位的数字,要将这个数字划分成n段,最后让这n段数字相乘,问怎么划分使乘积最大。 分析: 一

    相关 整数划分问题

    问题描述:将以正整数n表示成一系列正整数之和。 输入:整数N 输出:划分方法的总数。 //n为输入的整数,不同划分中最大加数不超过m,返回划分方法的总数。 int q(

    相关 整数划分--DP

    5. [数的划分][Link 1] 问题描述   将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。   例如:n=7,k=3,下面三种分法被认为是相同

    相关 整数划分 dp

    蒜头君特别喜欢数学。今天,蒜头君突发奇想:如果想要把一个正整数 nn 分解成不多于 kk 个正整数相加的形式,那么一共有多少种分解的方式呢? 蒜头君觉得这个问题实在是太难了,