您的位置:首页 > 其它

正整数划分问题(递归优化)

2010-09-08 17:30 260 查看
Description

将一个正整数n表示成一系列正整数的和,如:

N=n1+n2+…+nk(其中n1≥n2≥…≥nk≥1,k≥1)

正整数n的一个这种表示成为正整数n的一个划分。

现在给出一个正整数n(80≥n≥1),求n的不同划分一共有多少种。

Input

输入数据包含多组测试数据,每组测试数据只有一行,仅包含一个正整数n。

Output

对每组输入数据,输出一行,输出n的不同划分的种类数。

SampleInput

1
6

SampleOutput

1
11

links:http://jsj.sdibt.edu.cn/JudgeOnline/showproblem?problem_id=1497

算法课本上的对正整数划分的讲解如下:

在正整数n的所有不同的划分中,将最大加数n1不大于m的划分个数记做q(n,m)。可以建立q(n,m)的如下递归关系。

①q(n,m)=1,n>=1当最大加数n1不大于1时,任何正整数n只有一种划分形式,即n=1+1+1+~~~+1(n个1)

②q(n,m)=q(n,n),m>=n最大加数n1实际上不能大于n。因此,q(1,m)=1。

③q(n,n)=1+q(n,n-1)正整数n的划分由n1=n的划分和n1<=n-1的划分组成

④q(n,m)=q(n,m-1)+q(n-m,m)n>m>1正整数n的最大加数n1不大于m的划分由n1=m的划分和n1<=m-1的划分组成

PS:解释一下④n1=m时有:n1+n-m=n则此时的划分数目就是对n-m的划分,该划分中最大加数不大于m即:q(n-m,m)

由以上关系可得

intIntegerDivide(intn,intm) { if(n==1||m==1)return1; if(n==m)return(1+IntegerDivide(n,n-1)); if(n<m)returnIntegerDivide(n,n); if(n<1||m<1)return0; returnIntegerDivide(n,m-1)+IntegerDivide(n-m,m); }
众所周知,递归的效率并不是很高,当测试数据量很大的时候无法AC于是乎必须进行优化

intInDiv(intn,intm) { intj=m,re=0; while(j>=1) { if(n==j) { if(ss [j]==0)ss [j]==1; re+=ss [j];j--;continue; } if(n<j){j=n;continue;} if(n==1||m==1) { if(ss [j]==0)ss [j]==1; re+=ss [j];returnre; } if(ss [j]==0)InDiv(n-j,j); re+=ss [j]; j--; } returnre; }
采用循环替代了部分递归,貌似没有优化多少,依旧TL。。。


再次改进:

intss[81][81];
intIntegerDivide(intn,intm)
{
if(n==1||m==1)
{
if(ss
[m]==0)ss
[m]=1;
returnss
[m];
}
if(n==m)
{
if(ss
[m]==0)ss
[m]=1+IntegerDivide(n,n-1);
returnss
[m];
}
if(n<m)
{
if(ss
[m]==0)ss
[m]=IntegerDivide(n,n);
returnss
[m];
}
if(n<1||m<1)
{
return0;
}
if(ss
[m]==0)ss
[m]=IntegerDivide(n,m-1)+IntegerDivide(n-m,m);
returnss
[m];
}
对于已经计算过的q(n,m)进行存储提高了效率。。。

在网上看到别人写的代码附上挺牛的

#include
usingnamespacestd;
inti,j,sum[88],s[100][100];
intmain(){
s[0][0]=1;
for(i=1;i<=80;i++)
for(j=1;j<=i;j++)
{
s[i][j]=s[i-1][j-1]+s[i-j][j];
sum[i]+=s[i][j];
};
while(cin>>i)
{
cout<

直接从1开始一个递推的计算出1-80所有数的证书划分存入sum。。。时间复杂度O(n^2)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: