请教算法解决数学问题

taoy 2001-12-19 06:22:02
下面的问题可否用算法解决?
任意正整数例如100可以有多少种相加方式使其他正整数相加等于100。
比如100个1相加,98个1和1个2相加,.....99和1相加。
...全文
222 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
starfish 2001-12-22
  • 打赏
  • 举报
回复
wanbaocheng 说的也就是Ackman函数
已经从理论上证明了他是没有递推公式的,不要找了,呵呵
starfish 2001-12-22
  • 打赏
  • 举报
回复
就是Ackman函数,增长很快,是个二重递归
我记得有本pascal的教材上当作例题来说的
只要根据Ackman函数的递归公式计算即可
不可能找到递推公式的
所以这个问题没有什么难度


jinsong 2001-12-22
  • 打赏
  • 举报
回复
要是愿意讨论hjs791122@sina.com联系
jinsong 2001-12-22
  • 打赏
  • 举报
回复
可以用线性规划的方法求解上面的问题吗
taoy 2001-12-21
  • 打赏
  • 举报
回复
如果想知道具体的相加方式呢?
taoy 2001-12-21
  • 打赏
  • 举报
回复
如果我想具体的相加方式呢?
wanbaocheng 2001-12-21
  • 打赏
  • 举报
回复
To taoy:
你可以参考王晓东编著的《计算机算法设计与分析》一书上面有你的问题的一个等价问题,并有解法。如下:

整数划分问题
将一个正整数n表示成一系列正整数之和,
n = n1 + n2 + ... + nk,n1 >= n2 >= ...>= nk >=1,k >= 1。
正整数n的一个这种表示称为正整数n的一个划分。正整数n的所有不同划分的个数称为正整数n的划分数,记作p(n)。
例如正整数6有如下11种不同的划分,所以p(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。
在正整数n的所有不同划分中,将最大加数n1不大于m的划分个数记作q(n,m)。我们可以建立如下递推关系。
(1)q(n,1) = 1,n >= 1;
当最大加数n1不大于1时,任何正整数n只有一种划分形式,即n = 1 + 1 + ... + 1。
(2)q(n,m) = q(n,n),m >= n;
最大加数n1实际上不能大于n。因此,q(1,m) = 1。
(3)q(n,n) = 1 + q(n,n-1);
正整数n的划分由n1 = n 的划分和 n1<=(n-1)的划分组成。
(4)q(n,m) = q(n,m-1) + q(n-m,m),n > m >1;
正整数n的最大加数n1不大于m的划分由n1 = m的划分和n1 <= m-1 的划分组成。
以上的关系实际上给出了计算q(n,m)的递归式如下:
| 1 n = 1,m = 1
| q(n,n) n < m
q(n,m) =| 1+q(n,n-1) n = m
| q(n,m-1)+q(n-m,m) n > m > 1
据此,可设计计算q(n,m)的递归函数如下。正整数n的划分数p(n) = q(n,m)。
=========================================================================
int q(int n,int m)
{
if((n<1)||(m<1)) return 0;
if((n==1)||(m==1)) return 1;
if(n<m) return q(n,n);
if(n==m) return q(n,m-1)+1;
return q(n,m-1)+q(n-m,m);
}
=========================================================================
100的划分数为190569292

不过,我们容易发现这种递归方法效率不高。我记得在高中我在学习排列组合时曾经得到过你的问题的公式,时间久了,一时想不起思路,若你感兴趣,我们可再联系。
My Email: wanbaocheng@163.com
fastcall 2001-12-21
  • 打赏
  • 举报
回复
递归算法:
int taoy(int n)
{
if(n==2)
return 2;
else
{

int ret;
for(int i=1;i<n/2;i++)
{
ret=ret+taoy(i);
}
return ret;
}
}


mathe 2001-12-21
  • 打赏
  • 举报
回复
如果要列出具体的相加方法,那反而简单了,因为除了穷举已经没有更好的方法了。
不过对于比较大的n,比如n=200,那就等上一年的时间也就差不多了(不过如果你要保存结果,你的硬盘就遭殃了)。
andrew80 2001-12-20
  • 打赏
  • 举报
回复
整数拆分问题,用母函数(生成函数)求解,找本组合数学书看看.
如果用递归搜索效率没法忍受.
starfish 2001-12-20
  • 打赏
  • 举报
回复
好像就是Ackman函数吧
axial 2001-12-20
  • 打赏
  • 举报
回复
把一个数分解,我试过。
axial 2001-12-20
  • 打赏
  • 举报
回复
#include<stdio.h>
#include<conio.h>

#define MAXNUM 15
#define MAXSEQ 145
#define MYNUM 15

int a[MAXNUM][MAXSEQ][MYNUM];//data store

void main()
{
int i;//data flag which marks the result of different procession
int j;//composition method flag of some one data(i)
int k;//the datum position in some one composition method
int m;//the bigist integer not biger than i/2
int n;//the depth of drawback
int count;//used in print
int range;//used in print
int num;//your input number
int dj;//refreshing position(destination_j coresponding to j)

// system and data initialise
printf("\ninput a integer:");
scanf("%d",&num);
for(i=0;i<MAXNUM;i++)
{
for(j=0;j<MAXSEQ;j++)
{
for(k=0;k<MYNUM;k++)
{
a[i][j][k]=0;
}
}
}

// special procession of case 1
a[1][0][0]=1;//i:num j:composition sequence k:compositor from big to small
//a[i][j][0]:min compositor
a[1][0][1]=1;
i=2;j=0;k=0;

// begin processing from 2 to num
while(i<=num)
{
n=1;
m=i/2;
dj=0;
//special procession of case num
a[i][dj][0]=i;
a[i][dj][1]=i;
dj++;
// quote the existing sequence that contain min number n
while(n<=m)
{
//special procession of the first existing sequence
//it surely contains 2 data:min_flag and the quoted num(i-n)
//and they are equal
j=0;
k=0;
a[i][dj][0]=a[i-n][j][0];
a[i][dj][1]=a[i-n][j][1];
a[i][dj][2]=n;
a[i][dj][0]=n;
dj++;
j++;
//normal procession : quote and refresh
//auto detect which one can be quoted and refresh the min
while(a[i-n][j][0]!=0)
{
if(n<=a[i-n][j][0])
{
k=0;
while(a[i-n][j][k]!=0)
{
a[i][dj][k]=a[i-n][j][k];
k++;
}
a[i][dj][k]=n;
a[i][dj][0]=n;
dj++;
}
j++;
}
n++;
}
i++;
}

// print the result
count=1;
range=num;
for(i=range;i<=range;i++)
{
for(j=0;j<MAXSEQ;j++)
{
for(k=0;k<MYNUM;k++)
{
printf("%d ",a[i][j][k]);
}
printf("%d",count);
count++;
//if((count%25)==0)getch();
printf("\n");
if(a[i][j][k]==0)
{
break;
}
}
}
}
Arter 2001-12-20
  • 打赏
  • 举报
回复
整数的拆分!
taoy 2001-12-20
  • 打赏
  • 举报
回复
我知道要用递归,可是递归怎么写?
mathe 2001-12-20
  • 打赏
  • 举报
回复
代码需要改一下,你要的结果不是我所给得。写着写着就忘了问题所问的了。
#ifdef _WIN32
typedef uusngned __int64 longint;
#else
typedef unsigned long long longint;
#endif
#include <vector>
#include <iostream>
using namespace std;
vector<vector<longint> > F;
int main(){
int N,R,i;
cin>>N;
F.resize(N+1);
for(i=1;i<=N;i++)F[i].resize(i+1);
F[1][1]=1;
for(i=2;i<=N;i++){
F[i][1]=1;
for(j=2;j<=i;j++){
F[i][j]=0;
int k;
for(k=0;i-1-k*j>=j-1;k++){
F[i][j]+=F[i-1-k*j][j-1];
}
}
}
R=0;
for(i=1;i<=N;i++)R+=F[N][i];
cout<<R;
}
mathe 2001-12-20
  • 打赏
  • 举报
回复
另外贴一篇文章
整数的加法分析


每个正整数都可以唯一表示为素因子的乘积,所以说,
素数是正整数乘法表示的原子,如果把乘法换成加法,问题
就变得比较复杂。每一个整数有多种多样的加法表示,以5
为例:
5=5, 5=4+1, 5=3+2, 5=3+1+1, 5=2+2+1
5=3+1+1, 5=2+1+1+1, 5=1+1+1+1+1
其中两个极端是5=5和5=1+1+1+1+1,实际上每一个正
整数都有这两个极端的表示,但5=5不是一个标准的加法表
示,而5=1+1+1+1+1是平凡的加法表示,没什么意思。因此
正整数的加法表示需要具体分析。
首先,我们必须知道一个正整数到底有多少不同的分
析,这个数目我们称为分析数,用p(n)来表示,例如p(5)=7,
n小时,p(n)的数值如下:
p(1)=1
p(2)=2
p(3)=3
p(4)=5
p(5)=7
p(6)=11
p(7)=15
p(8)=22
p(9)=30
p(10)=42
显然,p(n)是增长很快的函数,实际上,可以算出:
p(100)=190,569,292
p(200)=3,972,999,029,388
即接近4万亿。因此要想通过手算找出p(n)的精确值是
很困难的事,即使靠计算机,算出p(10000)也并不容易。数
学家于是去求当n→∞,p(n)的渐进公式。1918年英国著名
数学家哈代和印度数学奇才拉马詹证明,当n→∞时,
1
p(n)~ ---------- eA×n^(1/2)
4n×3^(1/2)
其中,A=π×(2/3)^(1/2),这公式是说p(n)是随n指数增
长的。
为了研究正整数的加法分析的规律,数学家们转而研究
这些加法表示中有什么合乎规律的东西。在这方面,人们寻
找在这些加法表示中,是否每个数都能用一些特殊的数来进
行加法表示,如果可能需要用多少个。特殊的数有平方数、
立方数、素数以及图形数等等。而证明每一个正整数都能表
示为若干个这类特殊的数之和则是十分困难的问题,常常是
使数学家几十年几百年研究还不能解决的问题,最典型的就
是哥德巴赫猜想。
mathe 2001-12-20
  • 打赏
  • 举报
回复
记F(N,m)为将数字N才分为拆成m个自然数的和的方案(m个数不计顺序)。
其中,最小的数为1的种类有F(N-1,m-1)种。
而最小数为2的种类呢?
我们可以先去掉一个2,然后将余下的每一个数减一,正好对应于将
N-1-m拆成m-1个数的方案数,为F(N-1-m,m-1)
同样,最小数为3有F(N-1-2m,m-1)种,....
所以
F(N,m)=F(N-1,m-1)+F(N-1-m,m-1)+F(N-1-2m,m-1)+....
其中,初始条件为
F(N,1)=1,{即N=N的拆分}
F(N,N)=1,{即N=1+...+1的拆分}
F(x,y)=0,当x<y.
最终的结果为
F(N,N)+F(N,N-1)+...+F(N,1);
计算的方法可以如下:
#ifdef _WIN32
typedef uusngned __int64 longint;
#else
typedef unsigned long long longint;
#endif
#include <vector>
#include <iostream>
using namespace std;
vector<vector<longint> > F;
int main(){
int N,m,i;
cin>>N>>m;
F.resize(N+1);
for(i=1;i<=N;i++)F[i].resize(i+1);
F[1][1]=1;
for(i=2;i<=N;i++){
F[i][1]=1;
for(j=2;j<=i;j++){
F[i][j]=0;
int k;
for(k=0;i-1-k*j>=j-1;k++){
F[i][j]+=F[i-1-k*j][j-1];
}
}
}
cout<<F[N][m];
}
foxmike 2001-12-20
  • 打赏
  • 举报
回复
正整数拆分,组合数学书上讲过的。
你去找一本组合数学的书看看就知道了。
xilimi10 2001-12-19
  • 打赏
  • 举报
回复
可以用递归!
加载更多回复(2)

33,028

社区成员

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

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