整数划分

所谓整数划分,是指把一个正整数n写成如下形式:

n=m1+m2+...+mi; (其中mi为正整数,并且1 <= mi <= n),则{m1,m2,...,mi}为n的一个划分。

如果{m1,m2,...,mi}中的最大值不超过m,即max(m1,m2,...,mi)<=m,则称它属于n的一个m划分。这里我们记n的m划分的个数为f(n,m);

例如但n=4时,他有5个划分,{4},{3,1},{2,2},{2,1,1},{1,1,1,1};

注意4=1+3 和 4=3+1被认为是同一个划分。

 该问题是求出n的所有划分个数,即f(n, n)。下面我们考虑求f(n,m)的方法;

下面对n和m进行考虑

<1> if (n == 1 )  f(n,m) = 1;

<2> if(m == 1) f(n,m) = 1;

<3> if(n == m) 考虑划分中是否有n:a、如果包含n,那么f(n,m) = 1;b、如果不包含n,那么划分中最大的数一定比n小,所以f(n,m) = f(n,n-1)

所以f(n,n) = f(n,n-1) + 1

<4>if(n < m) 由于划分中最大的整数肯定是小于等于n 所以这种情况f(n,m) = f(n,n)

<5>if(n > m) 考虑划分中是否有m:a、如果包含m,即{m, {x1,x2,...xi}}, 其中{x1,x2,... xi} 的和为n-m,可能再次出现m,因此是(n-m)的m划分,那么f(n,m) = f(n-m,m)

       b、如果不包含m,即最大划分数为m-1,那么f(n,m) = f(n,m-1)

所以f(n,m) = f(n,m-1) + f(n-m,m)


综上可知:

int func(int n,int m)
{
	if(n == 1 || m == 1) return 1;
	else if(n < m ) return func(n,n);
	else if(n == m) return func(n,n-1) + 1;
	else return func(n-m,m) + func(n,m-1);
}

所以将整数n的所有划分个数为func(n,n)


POJ 1664 苹果放盘问题

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

(1):当盘子数为1的时候,只有一种放法就是把所有苹果放到一个盘子里。
(2):当苹果数为1的时候,也只有一种放法,注意题目中说明,盘子之间并无顺序,所以不管这个苹果放在哪个盘子里,结果都算一个。
(3):当m<n时,因为此时最多只能放到m个盘子中去(一个里放一个),实际上就相当于把m个苹果放到m个盘子里一样,也就是f(m,m);
(4):当m==n时,此时分两种情况讨论,一种是一个盘子里放一个,只是一种,第二种是,至少有一个盘子里不放苹果这就相当于是f(m,m-1);
(5):当m>n时,也分两种情况讨论,一种是至少有一个盘子里不放苹果,这样子就相当于f(m,n-1),第二种是,先取出n个苹果一个盘子里放一个,再将剩下的m-n个苹果放到n个盘子里去,即f(m-n,n);

可以发现就应该是func(m,n);


POJ 3014 Cake Pieces and Plates

这题题意其实和POJ1664是一样的,但是数据比较大,如果直接用递归的话铁定超时,这里有两种方法,第一种是记忆话递归,就是把递归过程中已经求出的值全部保存下来,下次再递归求这个值的时候直接返回就行了;第二种方法是迭代,也就是用DP

接下来给出DP的代码

int solve()  
{  
    for(int i = 1 ; i <= n ; i ++) dp[0][i] = 1;  
    for(int i = 1 ; i <= m ; i ++)  
    {  
        dp[i][0]=0;  
        for(int j = 1 ; j <= n ; j ++)  
             if(j > i)  dp[i][j] = dp[i][j-1];  
             else  
                 dp[i][j] = (dp[i-j][j] + dp[i][j-1]) % 1000000007;   
    }   
    return dp[m][n];  
} 

可以发现记忆化递归和DP的时间和空间负责度都是一样的。


思考题:1、如果盘子不为空怎么写?

        2、给定N需要求出具体的每一种划分?

比如N = 4

4 = 1 + 1 + 1 + 1

4 = 2 + 1 + 1

4 = 3 + 1

4 = 2 + 2

4 = 4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值