以题会友:求算法,一个整数N分解成m个加数的所有成立条件。

oldsky 2002-09-29 08:56:35
如:N=5 时可以有如下相加方法:
N=1+4
N=2+3
N=1+1+3
N=1+2+2
N=1+1+1+2
N=1+1+1+1+1
如何分解这个N,有多少个具体分法,求算法,要求效率。
...全文
296 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
starfish 2002-09-30
  • 打赏
  • 举报
回复
定义一个函数Q(M.N),表示整数M的“任何被加数都不超过N”的分划的数目。Q(M.N)有以下递归关系:
1)Q(M,1)=1,表示当最大的被加数是1时,该整数M只有一种分划,即M个1相加;
2)Q(1,N)=1,表示整数M=1只有一个分划,不管最大被加数的上限N是多大;
3)Q(M,N)=Q(M,M),如果M<N。很明显,M的分划不可能包含大于M的被加数N;
4)Q(M,M)=1+Q(M,M-1)。等式的右边分为两部分:第一部分的1表示M只包含一个被加数等于M本身的分划;第二部分表示M的所有其他分划的最大被加数N<=M-1,所以其他分划的数目就是等式右边的第二项。
5)Q(M,N)=Q(M,N-1)+Q(M-N,N),如果M>N。等式右边的第一部分表示被加数中不包含N的分划的数目;第二部分表示被加数中包含N的分划的数目,因为如果确定了一个分划的被加数中包含N,则剩下的部分可以按照对M-N的分划进行划分。
上述五个递归关系式对Q(M,N)作了递归定义。因为M的所有分划的数目P(M)=Q(M,M),所以上述关系式也定义了P(M)。

有了递归关系式后,解决问题的算法就非常简单了:

Partition(M, N)
1. if M < 1 or N < 1
2. then Error("输入参数错误")
3. else if M = 1 or N = 1
4. then return 1
5. else if M < N
6. then return Partition(M, M)
7. else if M = N
8. then return (1 + Partition(M, M-1))
9. else
10. return (Partition(M, N-1) + Partition(M-N, N));

注意,正整数的划分的数目随着M的增加增长的非常快(以指数级增长),所以不要用较大的整数来测试按照上述算法编写出的程序。
noall 2002-09-30
  • 打赏
  • 举报
回复
不过上面只能对正整数才可以。
想算法这么难。。。
noall 2002-09-30
  • 打赏
  • 举报
回复
一个memo,一个按钮,一个文本框(用来输入需要分解的值)
我这样做可以实现:但有几个问题:
function GetNum(S:string;Num:integer):string;
var I,J:integer;
Begin
for I:=1 to (Num div 2) do
begin
if (I>1 )and (Num<strtoint(edit1.Text)) then
break;//这一句写得不好
S:=S+'+'+IntToStr(I);
Mids:=S;
S:=S+'+'+IntToStr(Num-I);
memo1.Lines.Add(s);
if( I<>Num-I)and (num-I<>2) then
GetNum(Mids,Num-I);
S:=''//从新开始
end;
end;


procedure TForm1.Button2Click(Sender: TObject);
var mids,s:string;
begin
s:='';
memo1.Lines.Clear;
GetNum(S,strtoint(edit1.Text));
end;
我是这样想的:
如要分解的值是6则
有1+5
用mids保存1
再对5分解
1+4
这时mids保存1+1
接着对4进行分解.
。。。。
gofor 2002-09-30
  • 打赏
  • 举报
回复
海星的递归算法,可改为递推,速度很快。较大的数要注意整数溢出。
#include <iostream.h>
const M=100;
const N=100;
void main()
{
int a[M+1][N+1];
int i,j,m,n;
for (i=1; i<=N; i++) a[i][1]=1;
for (i=1; i<=M; i++) a[1][i]=1;
for (i=2; i<=M; i++)
for (j=2; j<=N; j++) {
if (i<j) a[i][j]=a[i][i];
else if (i>j) a[i][j]=a[i][j-1]+a[i-j][j];
else a[i][j]=a[i][i-1]+1;
}
cout<<"m, n=";
cin>>m>>n;
cout<<a[m][n];
cin>>i;
}
scorpiotianyawei 2002-09-30
  • 打赏
  • 举报
回复
你可以用循环来实现,x/1个循环,就可以
dcyu 2002-09-30
  • 打赏
  • 举报
回复
王晓东的书中有介绍的。
noall 2002-09-30
  • 打赏
  • 举报
回复
我的错了。


zzwdm 2002-09-30
  • 打赏
  • 举报
回复
递归
ukyoking 2002-09-30
  • 打赏
  • 举报
回复
如果仅仅只是想求出有多少种分法的话,可以考虑根据数字特征求出一个公式来,例如对n一般可以分成从1个到n个数相加,1个,n-1,n个显然各有一种,2个有n/2种,3个以上可以定义成把其中一个分成2个相加,依次类推,这样对于n非常大时可以保证效率
richardluopeng 2002-09-29
  • 打赏
  • 举报
回复
多重循环并判断
dcyu 2002-09-29
  • 打赏
  • 举报
回复
http://www.csdn.net/expert/topic/750/750682.xml?temp=.9988825
dylanOK 2002-09-29
  • 打赏
  • 举报
回复
up
yonghengdizhen 2002-09-29
  • 打赏
  • 举报
回复
用递归思想..(最基本的就是1了,作为递归退出条件)
然后将递归转换成适当的循环语句实现.
noall 2002-09-29
  • 打赏
  • 举报
回复
我的想法是:

先分为二个的

5=1+4
5=2+3

再对2、3、4每个继续拆分为二个(碰到1时退出)

最后组合起就是。





33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧