整数划分

描述
将正整数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

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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值