其中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
divide(n,m)表示将n个苹果放到至多n个盘子里,每个盘子里的苹果至多m个(可以有空盘子出现,这里的m表示的是盘子里的最大苹果数)。此题即是求divide(n,n)。
1.当n为1或m为1时,只有一种分法。
2.当n>m时,把少的苹果分到多的盘子里,那不用问肯定等于divide(n,n)了。
3.当n==m时,有两种情况,就是砍掉最后的。(1)分的这些苹果中有个里边有m个苹果,这里的m和n一样,就是有个盘子里装了n个苹果,所以就只有一种分法了。(2)这些盘子里没有一个里边有m个苹果,即最多的盘子也只装了n-1个,所以就转化为了求divide(n,n-1)。
4.当n<m时,也有两种情况,也是砍掉最后的m。(1)有个盘子里装着m个苹果,那么这个盘子就已经定下了,只管剩下的n-m个苹果和n-1个盘子就行了,就是divide(n-m,m)。(2)没有任何一个盘子里的苹果多于等于m个,即最多m-1个,所以就是divide(n,m-1)。
#include <stdio.h>
#include <stdlib.h>
int divide(int n, int m)
{
//printf("%d %d\n", n, m);
if(n == 1 || m == 1) return 1;
else if(n < m) return divide(n, n);
else if(n > m) return divide(n, m-1)+divide(n-m, m);
else return divide(n, m-1)+1;
}
int main()
{
int n, t;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
printf("%d\n", divide(n, n));
}
return 0;
}
另一种方法:深搜。一遍完成,无重复。
#include <stdio.h>
#define N 85
int Num, count;
void dfs(int cur, int start)
{
count ++;
if(cur == Num){
return;
}
for(int i = start; i < (Num - cur) / 2 + 1; i ++){ // i 最大为(Num - cur)的一半,否则后面的无法做递增,搜索无意义
dfs(cur + i, i);
}
}
int main()
{
count = 0;
scanf("%d", &Num);
for(int i = 1; i < Num / 2 + 1; i ++){ // 为避免重复, i 最大为Num的一半
dfs(i, i);
}
printf("%d\n", count);
return 0;
}
把一个正整数m分成n个正整数的和,有多少种分法?
例:把5分成3个正正数的和,有两种分法:
1 1 3
1 2 2
-
输入
- 第一行是一个整数T表示共有T组测试数据(T<=50)
每组测试数据都是两个正整数m,n,其中(1<=n<=m<=100),分别表示要拆分的正数和拆分的正整数的个数。
输出 - 输出拆分的方法的数目。
样例输入 -
2 5 2 5 3
样例输出 -
2 2
这个题可以用上边的方法引申,因为盘子不能空,所以先把每个盘子里摆上一个,然后剩下的再分就和上边一样了。代码如下,不同的是这里开始的n和m可能相等,如果不处理0的情况就会出错。
#include <stdio.h>
#include <stdlib.h>
int divide(int n, int m)
{
if(n == 1 || m == 1 || n == 0) return 1; //如果开始的n和m就想等话就必须处理n==0的情况。
else if(n>m) return divide(n-m, m)+divide(n, m-1);
else if(n < m) return divide(n, n);
else return divide(n, m-1)+1;
}
int main()
{
int n, t, m;
scanf("%d", &t);
while(t--)
{
scanf("%d %d", &n, &m);
printf("%d\n", divide(n-m, m));
}
return 0;
}
另外一种思路:把n个苹果分到m个盘子里。(m为盘子数,盘子不能为空)。
1.n>m:砍掉第一个最小的。(1)有一个盘子里刚好有一个,这时就是把n-m个分到m-1个盘子里,divide(n-m,m-1)。(2)所有的盘子里都大于等于2个,这时就是所有的盘子都先放好了一个,再分剩下的,divide(n-m,m)
2.n<m:不可能所有盘子都不空。0.
3.n等于m或者m为1,:1.
#include <stdio.h>
int divide(int n, int m)
{
if(m == 1 || n == m)
return 1;
if(n > m)
return divide(n-1, m-1)+divide(n-m,m);
if(n < m)
return 0;
}
int main()
{
int t, n, m;
scanf("%d", &t);
while(t--)
{
scanf("%d %d", &n, &m);
printf("%d\n", divide(n, m));
}
return 0;
}
还有一种更好的改进了的做法。就是把所有的数值都打表,因为有多组数据,所以把所有的可能数据都算出来存着,每输入一个直接取出来结果就行了。
#include <stdio.h>
int main()
{
int t, n, m, i, j, ans[103][103] = {0};
ans[1][1] = 1;
for(i = 2 ; i <= 100 ; i++)
for(j = 1 ; j <= i ; j++)
ans[i][j] = ans[i-1][j-1] + ans[i-j][j];
scanf("%d", &t);
while(t--)
{
scanf("%d %d", &n, &m);
printf("%d\n", ans[n][m]);
}
return 0;
}