1009. 整数的拆分

单点时限: 2.0 sec

内存限制: 256 MB

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

例如,正整数 3 有如下 3 种不同的拆分 :

3;

2+1;

1+1+1。

输入格式
本题有多组测试数据,每组一行,每行有一个正整数 N(1<=N<=100)

输出格式
每组测试数据输出一行,表示有多少种拆分方法

样例
input
1
3
5
output
1
3
7
整数划分百度

一个数n可以看成背包容量为n的背包,f[n]由n个价值和花费分别为i 的物品,能装满背包的种类数,而每种物品的数量不限,正好是一个完全背包问题。

    int f[1000];
    memset(f,0,sizeof(f));
    f[0]=1;//注意这里很重要
    for(int i=1; i<=n; i++)
        for(int j=i; j<=n; j++)
            f[j]=f[j]+f[j-i];

根据n和m的关系,考虑下面几种情况:
(1)当n=1时,不论m的值为多少(m>0),只有一种划分,即{1};
(2)当m=1时,不论 的值为多少(n>0),只有一种划分,即{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,{x1,x2,x3,…,xi}},其中{x1,x2,x3,…,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)为通用情况,属于递归的方法,其本质主要是通过减少n或m以达到回归条件,从而解决问题。
详细递推公式描述如下:
在这里插入图片描述


#include<iostream>
using namespace std;
int main()
{
    int n;
    int dp[109][109];
    for(int i = 1; i < 109; i++)
    dp[i][1]=dp[1][i]=1;
    for(int i = 2; i < 109; i++)
    {
    	for(int j = 2; j < 109; j++)
    	{
    	    if(i<j)
    		dp[i][j]=dp[i][i];
    		else if(i==j)
    		dp[i][j]=1+dp[i][j-1];
    		else
    		dp[i][j]=dp[i][j-1]+dp[i-j][j];
		}
	}
   
    while(scanf("%d",&n)!=EOF)
    {
        cout<<dp[n][n]<<endl;
    }
    return 0; 
}

猜你喜欢

转载自blog.csdn.net/qq_40394960/article/details/105877990