2014北大研究生推免机试(校内)-复杂的整数划分(DP进阶)
这是一道典型的整数划分题目,适合正在研究动态规划的同学练练手,但是和上一个随笔一样,我是在Coursera中评测通过的,没有找到适合的OJ有这一道题(找到的ACMer拜托告诉一声~),这道题考察得较全面,考察了三种整数划分的变形问题。
Openjudge 原题网址:Bailian2014研究生推免上机考试(校内)
原题:
- Description
-
将正整数n 表示成一系列正整数之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1 。
正整数n 的这种表示称为正整数n 的划分。 - Input
- 标准的输入包含若干组测试数据。每组测试数据是一行输入数据,包括两个整数N 和 K。
(0 < N <= 50, 0 < K <= N) - Output
- 对于每组测试数据,输出以下三行数据:
第一行: N划分成K个正整数之和的划分数目
第二行: N划分成若干个不同正整数之和的划分数目
第三行: N划分成若干个奇正整数之和的划分数目 - Sample Input
-
5 2
- Sample Output
-
2 3 3
- Hint
- 第一行: 4+1, 3+2,
第二行: 5,4+1,3+2
第三行: 5,1+1+3, 1+1+1+1+1+1
有关这三种变形问题的具体解释在我的另一篇随笔中有提及:整数划分问题-解法汇总,看不懂Code的ACMer见这篇随笔。
Code如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 6 #define MAX 51 7 8 int dp1[MAX][MAX]; 9 int dp2[MAX][MAX]; 10 int dp3[MAX][MAX]; 11 12 /*划分成K个整数*/ 13 void DP1() 14 { 15 for (int n = 1; n < MAX; n++) 16 { 17 for (int k = 1; k < MAX; k++) 18 { 19 if (n == k || k == 1) 20 dp1[n][k] = 1; 21 else if (n > k) 22 dp1[n][k] = dp1[n - k][k] + dp1[n - 1][k - 1]; //划分中不包含1 + 划分中至少有一个1 23 } 24 } 25 } 26 27 /*划分成<=m的不同整数*/ 28 void DP2() 29 { 30 for (int n = 1; n < MAX; n++) 31 { 32 for (int m = 1; m < MAX; m++) 33 { 34 if (n > m) //除m外的数不包括m(即剩下划分总和为n-m中没有m) 35 dp2[n][m] = dp2[n - m][m - 1] + dp2[n][m - 1]; 36 else if (n < m) 37 dp2[n][m] = dp2[n][n]; 38 else 39 dp2[n][m] = 1 + dp2[n][m - 1]; 40 } 41 } 42 } 43 44 /*划分成<=m的奇正整数*/ 45 void DP3() 46 { 47 for (int n = 1; n < MAX; n++) //+1不会增加种类 48 { 49 for (int m = 1; m < MAX; m+=2) 50 { 51 if (n > m) 52 dp3[n][m] = dp3[n - m][m] + dp3[n][m - 1]; 53 else if (n < m) 54 dp3[n][m] = dp3[n][n]; 55 else 56 dp3[n][m] = 1 + dp3[n][m - 1]; 57 dp3[n][m + 1] = dp3[n][m]; 58 } 59 } 60 } 61 62 int main() 63 { 64 DP1(); 65 DP2(); 66 DP3(); 67 int num, k; 68 while (scanf("%d%d", &num, &k) != EOF) 69 { 70 printf("%d\n", dp1[num][k]); 71 printf("%d\n", dp2[num][num]); 72 printf("%d\n", dp3[num][num]); 73 } 74 75 return 0; 76 }
他坐在湖边,望向天空,她坐在对岸,盯着湖面