整数划分
时间限制:3000 ms | 内存限制:65535 KB
难度:3
- 描述
- 将正整数n表示成一系列正整数之和:n=n1+n2+…+nk,
其中n1≥n2≥…≥nk≥1,k≥1。
正整数n的这种表示称为正整数n的划分。求正整数n的不
同划分个数。
例如正整数6有如下11种不同的划分:
6;
5+1;
4+2,4+1+1;
3+3,3+2+1,3+1+1+1;
2+2+2,2+2+1+1,2+1+1+1+1;
1+1+1+1+1+1。
- 输入
- 第一行是测试数据的数目M(1<=M<=10)。以下每行均包含一个整数n(1<=n<=10)。
- 输出
- 输出每组测试数据有多少种分法。
- 样例输入
-
1 6
- 样例输出
-
11
解析:根据n和m的关系,考虑以下几种情况:
(1)当n=1时,不论m的值为多少(m>0),只有一种划分即{1};
(2) 当m=1时,不论n的值为多少,只有一种划分即n个1,{1,1,1,...,1};
(3) 当n=m时,根据划分中是否包含n,可以分为两种情况:
(a). 划分中包含n的情况,只有一个即{n};
(b). 划分中不包含n的情况,这时划分中最大的数字也一定比n小,即n的所有(n-1)划分。
因此 f(n,n) =1 + f(n,n-1);
(4) 当n<m时,由于划分中不可能出现负数,因此就相当于f(n,n);
(5) 但n>m时,根据划分中是否包含最大值m,可以分为两种情况:
(a). 划分中包含m的情况,即{m, {x1,x2,...xi}}, 其中{x1,x2,... xi} 的和为n-m,可能再次出现m,因此是(n-m)的m划分,因此这种划分
个数为f(n-m, m);
(b). 划分中不包含m的情况,则划分中所有值都比m小,即n的(m-1)划分,个数为f(n,m-1);
因此 f(n, m) = f(n-m, m)+f(n,m-1);
1 #include <cstdio> 2 #include <iostream> 3 4 using namespace std; 5 6 int fun(int n, int m) // fun(n, m)表示将整数 n 划分为最大数不超过 m 的划分 7 { 8 if(n == 1 || m == 1) 9 return 1; 10 if(n < m) 11 return fun(n, n); 12 if(n > m) // 此时将问题转化为两部分 1.划分中含有 m; 2.划分中不含 m 13 return fun(n-m, m) + fun(n, m-1); 14 if(n == m)// 此时也是两部分,如果含有 m 则只有一种只含有 m 的划分,如果不含有 m 则转化为最大数不超过 m-1 的划分 15 return 1 + fun(n, m-1); 16 } 17 18 int main() 19 { 20 int T, n; 21 scanf("%d", &T); 22 while(T--) 23 { 24 scanf("%d", &n); 25 printf("%d\n", fun(n,n)); 26 } 27 return 0; 28 }