关于C语言处理大数问题,我写的方法效率太差,请问一下有没有高效一点的算法?

ww884203 2011-07-20 09:04:37
问题是这样的:给出一个正整数n(n<100),求一个最小的整数m使得m能整除1,2,3...n的所有数
也就是求从1~n所有数的最小公倍数。
我的算法思想就是首先m = n,然后让m = m 与 n-1的最小公倍数,然后是m与n-2的最小公倍数,直到m与2的最小公倍数。
由于n很大时得出的数据也很大,需要用大数,我自己写了一个感觉效率太差了,大家有什么高效的算法么?
后面附上我写的代码,很烂,大家也可以不看。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
*Question 3
*给出一个正整数n(n<100),求一个最小的整数m使得m能整除1,2,3...n的所有数
*问题的算法思想并不难,关键在于大数的处理
*大数的处理思想为,用一个int数组,其中每一个int存储大数的一位数
*/

#define MAX 50

/*
*令数组的每一位都恢复到合法值
*/
void Check(int Digit[])
{
int iter;
for(iter = 0 ; iter != MAX-1 ; ++iter)
{
while(Digit[iter] < 0)
{
Digit[iter] += 10;
Digit[iter+1] -=1;
}
while(Digit[iter] > 9)
{
Digit[iter] -= 10;
Digit[iter+1] +=1;
}
}
}

void Output(int Digit[])
{
int iter;
for(iter = MAX-2 ; iter != -1 ; --iter)
{
if(Digit[iter] != 0)break;
}
for( ; iter != -1 ; --iter)
{
printf("%d",Digit[iter]);
}
printf("\n");
}


/*
*是否大于
*/
int IsBigger(int Digit[], int cmp)
{
int iter;
static int Temp[MAX];
memset(Temp,0,sizeof(Temp));
Temp[0] = cmp;
Check(Temp);
for(iter = MAX-2 ; iter != -1 ; --iter)
{
if(Temp[iter] > Digit[iter]) return 0 ;
else if(Temp[iter] < Digit[iter]) return 1;
}
return 1;
}

/*
*大数与int直接作减法
*/

void Sub(int Digit[] , int sub)
{
Digit[0] -= sub;
Check(Digit);
}

/*
*大数与int直接作加法
*/

void Add(int Digit[] , int add)
{
Digit[0] += add;
Check(Digit);
}

void Mul(int Digit[] , int mul)
{
int iter;
for(iter = 0 ; iter != MAX ; iter++)
{
Digit[iter] *= mul;
}
Check(Digit);
}


/*
*判断是不是0
*/
int IsZero(int Digit[])
{
int iter;
for(iter = 0 ; iter != MAX ; ++iter)
{
if(Digit[iter] != 0) return 0;
}
return 1;
}


/*
*转化
*/
void Set(int Digit[] , int data)
{
int iter = 0;
memset(Digit,0,sizeof(int) * MAX);
while(data != 0)
{
Digit[iter] = data%10;
data /= 10;
iter++;
}
}

int Get(int Digit[])
{
int data = 0;
int iter;
for(iter = MAX-2 ; iter != -1 ; --iter)
{
data = data*10 + Digit[iter];
}
return data;
}

/*
*求余数
*/
int Mod(int Digit[] , int num)
{
while(1)
{
if(IsBigger(Digit,num))
{
Sub(Digit,num);
}
else
{
return Get(Digit);
}
}
}

int gcd(int Digit[] , int cmp)
{
int mod = Mod(Digit,cmp);
while(mod != 0)
{
Set(Digit,cmp);
cmp = mod;
mod = Mod(Digit,mod);
}
return cmp;
}

int main()
{
int input,iter;
int output[MAX];
int Buffer[MAX];
memset(output,0,sizeof(output));
scanf("%d",&input);
output[0] = input;
Check(output);
for(iter = input ; iter != 1 ; --iter)
{
memcpy(Buffer,output,sizeof(output));
Mul(output,iter/gcd(Buffer,iter));
}
Output(output);
return 0;
}

...全文
402 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
风中舞者 2011-07-20
  • 打赏
  • 举报
回复
首先n/2一下的数不需要考虑。
维护一份n以内的所有素数的数组Arr(为了简单也可以直接维护一个100的数组,也没多少开销)。

对m(从n开始向下到n/2)依次处理:获取m的素数集合(A1,A2...As)及对应的素数的个数(B1,B2...Bs),根据这个素数集合维护素数数组Arr,如果Arr中Ai(1<=i<=s)对应的值Arr[Ai]小于Bi,则更新arr[Ai]=Bi。
将Arr中所有个数大于1的素数Ai累乘Arr[Ai]次,即得到最后结果。

时间开销主要在获取n/2个数的素数集合。可以想想还有没有什么优化的办法。
ww884203 2011-07-20
  • 打赏
  • 举报
回复
楼上的代码我再细细研究一下。。。
另外上面有说只要质数相乘就行的,我觉得不行吧,比如n=4,质数只有2和3,相乘得6,但是6不是4的倍数吧
另外,这正是考题。。。没法用库,不过我去参考下他们的做法,呵呵
mLee79 2011-07-20
  • 打赏
  • 举报
回复
弄了个最平凡的, 算1W以内的, 好像也够用了, 就不做优化了...

#include <stdio.h>

int mul( int len , int v[] , int b )
{
int i;
v[len] = 0;
for( i = 0; i < len; ++i )
v[i] *= b;
for( i = 0; i < len; ++i )
{
v[i+1] += v[i] / 10000;
v[i] %= 10000;
}
if( v[len] ) ++len;
return len;
}

#define MAXN 10000

void slove( int n )
{
int i , j ;
int f[MAXN+2] = {0};
int r[MAXN*4] = {1} , len = 1;

for( i = 2; i <= n; ++i )
{
int x = i;
for( j = 2; j <= x; ++j )
{
if( x % j == 0 ) {
int c = 0;
do
{
++c;
x /= j;
} while( x % j == 0 );

if( c > f[j] ) f[j] = c;
}
}
}

for( i = 2; i <= n ; ++i )
{
while( f[i] )
{
--f[i];
len = mul( len , r , i );
}
}

printf( "%d" , r[len-1] );
for( i = len-2; i >= 0; --i )
printf( "%04d" , r[i] );
printf( "\n" );
}

int main()
{
int n;
while( 1 == scanf( "%d" , &n ) && n > 0 && n <= MAXN )
slove( n );
return 0;
}

mLee79 2011-07-20
  • 打赏
  • 举报
回复
这个你把 1...100 做因数分解, 不用啥大数运算哈...
quwei197874 2011-07-20
  • 打赏
  • 举报
回复
用字符数组
mLee79 2011-07-20
  • 打赏
  • 举报
回复
这个几百位的用不着动用gmp吧. 非常平凡的算法即可.
你怎么也得搞成 2^32 进制或者 10^9 进制啥的吧, 10进制的也太不平凡了吧.
xunxun 2011-07-20
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 babilife 的回复:]

引用 2 楼 xunxun1982 的回复:
大数算法可以参考 gmplib的做法,开源的,使用了SIMD



+++1 ,如果不是考题,请参考大数库吧,顺便恭喜楼上升星,你该散点分了
[/Quote]
怎么散法?我还没发过主题贴
至善者善之敌 2011-07-20
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 xunxun1982 的回复:]
大数算法可以参考 gmplib的做法,开源的,使用了SIMD
[/Quote]


+++1 ,如果不是考题,请参考大数库吧,顺便恭喜楼上升星,你该散点分了
alweeq86 2011-07-20
  • 打赏
  • 举报
回复
问题是这样的:给出一个正整数n(n<100),求一个最小的整数m使得m能整除1,2,3...n的所有数

找出1~n中所有的素数 m就是这些质数的积
xunxun 2011-07-20
  • 打赏
  • 举报
回复
大数算法可以参考 gmplib的做法,开源的,使用了SIMD
wstc875 2011-07-20
  • 打赏
  • 举报
回复
其实一个int可以存好几位,小于10000的都可以,存1位是否少了点

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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