整数划分

来源:互联网 发布:mac install ant 编辑:程序博客网 时间:2024/05/16 17:47

题目:点击打开链接

(一)递归法



       根据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)和(2)属于回归条件,(3)和(4)属于特殊情况,将会转换为情况(5)。而情况(5)为通用情况,属于递推的方法,其本质主要是通过减小m以达到回归条件,从而解决问题。其递推表达式如下:

         f(n, m) =      1;                                        ( n = 1 or m = 1 )

                            f(n, n);                                 ( n < m )

                            1+ f(n, m - 1);                      ( n = m )

                            f(n - m, m) + f(n, m - 1);       ( n > m )


AC代码:

#include <stdio.h>int f[121][121];void init( ){    int i, j;    for(i = 1; i <= 120; i++)        f[i][1] = f[1][i] = 1;    for(i = 2; i <= 120; i++)    {        for(j = 2 ; j <= 120; j++)        {            if(i < j)                f[i][j]= f[i][i];           else  if(i == j)                f[i][j] = 1+ f[i][j-1];            else                f[i][j] = f[i-j][j] + f[i][j-1];        }    }}int main (void){    int i;    init();    while(scanf("%d", &i) != EOF)        printf("%d\n", f[i][i]);        return 0;}


2, 母函数的方法:

http://www.cnblogs.com/hoodlum1980/archive/2008/10/11/1308493.html

这里面讲的很清楚:



#include <stdio.h>
#define MAX 120

int c1[MAX+5],c2[MAX+5];

int main()
{

    int i,k,j,n;
    for(i=0;i<=MAX;i++)    //单位指数为1的时候
    {
        c1[i]=1;
        c2[i]=0;
    }
    for(i=2;i<=MAX;i++)        //单位指数分别为2`n的时候
    {
        for(j=0;j<=MAX;j++)//遍历前一个多项式就是前面已经相乘的多项式
            for(k=0;k+j<=MAX;k+=i)    //遍历下一个多项式
                c2[j+k]+=c1[j]; //把结果存在C2[]中,c1[]为前i-1多项式的乘积结果;应为后一个多项式的每一项前面系数都是1,所以直接累加;
        for(j=0;j<=MAX;j++)
        {
            c1[j]=c2[j];        //把结果赋值给c1[],便于循环
            c2[j]=0;
        }
    }
    while(scanf("%d",&n)!=EOF)
        printf("%d\n",c1[n]);
    return 0;
}

这个题目是最基本的,每一种数都没有限制,可以再思考一下当规定谋写数的数量的时候,情况又会是怎么样的?


#include <stdio.h>
#include <string.h>
#define maxn 125
#define Max(A,B) ( (A) > (B) ? (A) : (B) )

int dp[maxn];/*dp[i]表示整数i的分配个数*/
/*相当于一个完全背包*/
/*每一个数字就是物品.价值是数字本身,费用也是数字本身*/

void DP()
{
    memset(dp,0,sizeof(dp));
    dp[0] = 1 ;
    for(int i = 1 ; i <= maxn ; i++)/*表示的是第i个数字*/
        for(int j = i ; j <= maxn ; j++)
            dp[j] += dp[j-i];
}

int main()
{
    int N;

    DP();
    while(scanf("%d",&N) != EOF)
        printf("%d\n",dp[N]);
    return 0;
}



这个代码是别人写的,没有懂其中的意思,但是可以提醒我们怎么转化问题,怎么来讲具体的问题抽象出来,

转换为我们所熟知的问题和解法;



0 0
原创粉丝点击