正整数划分问题(递归优化)
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
SampleOutput
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;
}
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<
将一个正整数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:
算法课本上的对正整数划分的讲解如下:
在正整数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)
由以上关系可得
众所周知,递归的效率并不是很高,当测试数据量很大的时候无法AC于是乎必须进行优化
采用循环替代了部分递归,貌似没有优化多少,依旧TL。。。
再次改进:
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)进行存储提高了效率。。。
在网上看到别人写的代码附上挺牛的
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)
相关文章推荐
- 算法(1)整数划分问题之递归解决
- 数据结构:整数划分问题 + DFS递归解决
- 递归 放苹果问题和整数划分问题
- 递归--整数划分问题
- 11088 整数划分的扩展问题(递归,分治)
- 递归 放苹果问题和整数划分问题
- 整数划分问题---动态规划、递归
- 递归---整数划分问题
- 0002算法笔记——【递归】排列问题,整数划分问题,Hanoi问题
- 递归之整数的划分问题
- 递归——整数划分问题
- 递归 放苹果问题和整数划分问题
- 整数划分问题(递归)
- 跳台阶问题|斐波那契递归的复杂度问题|整数划分问题
- YTU.3131: 进阶递归之简单的整数划分问题
- 递归和分治——整数划分问题
- 整数划分问题之递归法
- 递归 放苹果问题和整数划分问题
- 整数划分问题---动态规划、递归
- 递归-整数划分问题