程序设计实习MOOC/第十三周编程作业/C:UNIMODAL PALINDROMIC DECOMPOSITIONS(Greater New York 2002)
2014-05-20 20:32
781 查看
题目:C:UNIMODAL PALINDROMIC DECOMPOSITIONS 总时间限制: 1000ms 内存限制: 65536kB 描述 A sequence of positive integers is Palindromic if it reads the same forward and backward. For example: 23 11 15 1 37 37 1 15 11 23 1 1 2 3 4 7 7 10 7 7 4 3 2 1 1 A Palindromic sequence is Unimodal Palindromic if the values do not decrease up to the middle value and then (since the sequence is palindromic) do not increase from the middle to the end For example, the first example sequence above is NOT Unimodal Palindromic while the second example is. A Unimodal Palindromic sequence is a Unimodal Palindromic Decomposition of an integer N, if the sum of the integers in the sequence is N. For example, all of the Unimodal Palindromic Decompositions of the first few integers are given below: 1: (1) 2: (2), (1 1) 3: (3), (1 1 1) 4: (4), (1 2 1), (2 2), (1 1 1 1) 5: (5), (1 3 1), (1 1 1 1 1) 6: (6), (1 4 1), (2 2 2), (1 1 2 1 1), (3 3), (1 2 2 1), ( 1 1 1 1 1 1) 7: (7), (1 5 1), (2 3 2), (1 1 3 1 1), (1 1 1 1 1 1 1) 8: (8), (1 6 1), (2 4 2), (1 1 4 1 1), (1 2 2 2 1), (1 1 1 2 1 1 1), ( 4 4), (1 3 3 1), (2 2 2 2), (1 1 2 2 1 1), (1 1 1 1 1 1 1 1) Write a program, which computes the number of Unimodal Palindromic Decompositions of an integer. 输入 Input consists of a sequence of positive integers, one per line ending with a 0 (zero) indicating the end. 输出 For each input value except the last, the output is a line containing the input value followed by a space, then the number of Unimodal Palindromic Decompositions of the input value. See the example on the next page. 样例输入 2 3 4 5 6 7 8 10 23 24 131 213 92 0 样例输出 2 2 3 2 4 4 5 3 6 7 7 5 8 11 10 17 23 104 24 199 131 5010688 213 1055852590 92 331143 提示 N < 250
解题思路:
dp[i][j]表示i分解成最大元素不超过j的整数之和的方案数(每种方案自然可以对应成一个不递减的序列) 类似于背包问题,它代表用1,2,3...j这些数字,每个数字可以取任意多个,使得和为i,有多少种方式 分解成子问题,即选取的j的个数确定时(设为k个),剩余整数之和i-k*j分解成最大元素不超过j-1的方案数之和 dp[i][j] = dp[i - 0*j][j - 1](j取0个,i分解成最大元素不超过j-1) + dp[i - 1*j][j - 1](j取1个,所以剩余的为i-j分解成最大元素不超过j-1) + dp[i - 2*j][j - 1](j取2个,所以剩余的为i-2*j分解成最大元素不超过j-1) + ... 一直加到"i - k*p < 0"结束 dp[i][i]求到的是i分解成最大元素不超过i的整数之和的方案数,即单调不递减序列 这里求的是单峰回文序列,即单调不递减再单调不递增,后面与前面是对应的,所以, 对于奇数i,只有一种情况, 枚举中间取值(会是奇数),设为mid,左边就是个单调不递减序列, 对于每一个mid值,都有方案数dp[(i-mid)/2][min((i-mid)/2, mid//有mid是确保mid前的元素不会超过mid,保持单调不递减)], 因为右边和左边相对应,所以左边每一种方案,右边都是唯一确定的, 如 7: (7), (1 5 1), (2 3 2), (1 1 3 1 1), (1 1 1 1 1 1 1) mid 取 7,dp[(7-7)/2][min((7-7)/2, 7)] = 1//mid自己本身就是一种方案 mid 取 5,dp[(7-5)/2][min((7-5)/2, 5)] = 1 mid 取 3,dp[(7-3)/2][min((7-3)/2, 3)] = dp[2][2] = 2,即2可分为1 1和2,回文的,所以后面是唯一对应的 mid 取 1,dp[(7-1)/2][min((7-1)/2, 1)] = dp[3][1] = 1,即3分为1 1 1(最大元素不超过1),回文的,所以后面是唯一对应的 对于偶数i,分为两种情况, 如8:第一类(8), (1 6 1), (2 4 2), (1 1 4 1 1), (1 2 2 2 1),(1 1 1 2 1 1 1); mid取8,6,4,2,对应dp[0][0] + dp[1][1] + dp[2][2] + dp[3][2] = 1 + 1 + 2 + 2 注意不能包含mid取0的情况,因为dp[0][0]等于1,多加了1会导致结果有问题 第二类(4 4), (1 3 3 1), (2 2 2 2),(1 1 2 2 1 1), (1 1 1 1 1 1 1 1)。 dp[i/2][i/2] = dp[4][4] = 5
代码如下:
#include<iostream> #include<algorithm> using namespace std; #define NUM 250 int main() { int dp[NUM][NUM]; for(int i = 0; i < NUM; i++) { dp[i][0] = 1; dp[0][i] = 1;//注意初始化为1,是因为会有一种i仅仅由j组成序列的情况(如(4,2):4 = 2 + 2,(8,4):8 = 4 + 4) //如dp[2][2] = dp[2 - 0][1] + dp[2 - 1*2][1](这里该是1,对应了"2"这种情况) //又如dp[3][2] = dp[3][1] + dp[3 -1*2][1] = 1 + 1(是dp[1][1],也是一种情况,没有dp[0][1],所以不会额外多加了1) //又如dp[4][2] = dp[4][1] + dp[4 - 1*2][1] + dp[4 - 2*2][1](这里该是1,对应了2个2,即"2 2"这种情况) //又如dp[4][4] = dp[4][3] + dp[4 - 1*4][3](这里该是1,对应了1个4,即"4"这种情况) //又如dp[6][4] = dp[6][3] + dp[6 - 1*4][3](是dp[2][3],也是一种情况,没有dp[0][3],所以不会额外多加了1) }//设置边界状态的值 for(int i = 1; i < NUM; i++) dp[i][1] = 1;//设置边界状态的值 for(int i = 1; i < NUM; i++) { for(int j = 2; j < NUM; j++) { dp[i][j] = dp[i - 0 * j][j - 1]; int k = 1; while(i - k * j >= 0) { dp[i][j] += dp[i - k * j][j - 1]; k++; } } } /* for(int i = 0; i < NUM; i++) { for(int j = 0; j < NUM; j++) cout << dp[i][j] << " "; cout <<endl; } */ int i; long long num;//数值太大,使用long long型,防止溢出 cin >> i; while(i) { num = 0; if(i % 2 == 1)//奇数 { for(int mid = i; mid > 0; mid -= 2) num += dp[(i - mid) / 2][min((i - mid) / 2, mid)]; } else//偶数 { for(int mid = i; mid > 0; mid -= 2) num += dp[(i - mid) / 2][min((i - mid) / 2, mid)]; num += dp[(i/2)][(i/2)]; } cout << i << " " << num <<endl; cin >> i; } system("pause"); return 0; }
相关文章推荐
- 程序设计实习MOOC/第十三周编程作业/A:集合加法
- 北大程序设计实习MOOC 编程作业 《魔兽世界之二:装备》
- 【北大MOOC】2014程序设计实习--第二周编程作业
- 程序设计实习MOOC/第十五周编程作业/A:棋盘问题
- 程序设计实习MOOC / 继承和派生——编程作业 第五周程序填空题1
- 北大程序设计实习公开课编程作业,魔兽世界之二:装备
- 程序设计实习MOOC/第十三周编程作业/B:木材加工(NOIP 2004)
- 程序设计实习MOOC / 继承和派生——编程作业 第五周程序填空题1
- 北大程序设计实习公开课编程作业,魔兽世界之一:备战
- 2015 程序设计实习之动规作业2
- 2015 程序设计实习之递归作业
- 程序设计入门—Java语言 . 翁恺-第四周编程作业-2.念整数
- 2017 程序设计实习之C++部分作业题汇总 - H:STL 容器与算法
- 程序设计基础(C&C++) 戴波、张东祥 第六章 函数 编程作业
- MOOC 程序设计基础(C&C++) 戴波、张东祥 第五章 指针 作业
- 程序设计基础(C&C++) 戴波、张东祥 第四章 数组与结构 编程作业
- 2017 程序设计实习之C++部分作业题汇总 - F:模板 template
- MOOC清华《VC++面向对象与可视化程序设计》第2章:编程作业-渐变图形的绘制(“万花筒”程序)
- MOOC 程序设计基础(C&C++) 戴波、张东祥 第四章 数组与结构 作业
- 2017 程序设计实习之C++部分作业题汇总 - B:面向对象基础