【求助】有关于最大公约数的一个问题!

w602174096 2012-10-05 07:55:29
有一道题是求:
一个整数N,找出所有小于它的正整数的个数,并且这个正整数与它的最大公约数为1.

样例:
对于25608有7680个符合这个条件的正整数。

我的思路:
从1开始,找出与它的最大公约数大于1的一个数,比如说2,然后将2,4,6,8……(2*n<N)记录下来,然后后面的这些就不用找了,最后知道所有的都找完。这个算法的时间太长了,勉强过了。希望哪位大神给出耗时很少的算法!
...全文
145 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
jackyjkchen 2012-10-05
  • 打赏
  • 举报
回复
不用筛选法,0.6s
jackyjkchen 2012-10-05
  • 打赏
  • 举报
回复
按你的思路筛选法,x=1000000,耗时0.2s,我是x64的,x86的请将ulong64改成uint


#include <stdio.h>
#include <Windows.h>

inline BOOLEAN IsEven(ULONG64 x)
{
if (x & 0x01ULL)
return FALSE;
else
return TRUE;
}

ULONG64 GCD(ULONG64 x, ULONG64 y)
{
if (x < y)
return GCD(y, x);
if (y == 0)
return x;
else
{
if (IsEven(x))
{
if (IsEven(y))
return GCD(x>>1, y>>1) << 1;
else
return GCD(x>>1, y);
}
else
{
if (IsEven(y))
return GCD(x, y>>1);
else
return GCD(y, x-y);
}
}
}

void TimeStart(LARGE_INTEGER *pBegintime)
{
QueryPerformanceCounter(pBegintime);
}

LPSTR TimeResult(LARGE_INTEGER *pBegintime, LPSTR szTime)
{
LARGE_INTEGER endtime;
LARGE_INTEGER freqtime;
LARGE_INTEGER resulttime;
QueryPerformanceCounter(&endtime);
QueryPerformanceFrequency(&freqtime);
resulttime.QuadPart = (endtime.QuadPart - pBegintime->QuadPart) * 1000 / freqtime.QuadPart;
sprintf(szTime, "%I64d小时%I64d分%I64d.%03I64d秒", resulttime.QuadPart / 3600000, (resulttime.QuadPart / 60000) % 60, (resulttime.QuadPart /1000) % 60, resulttime.QuadPart % 1000);
return szTime;
}

int main()
{
const int x = 2560800;
int i = 0, count = 0, j = 0, n = 0;
unsigned char *tab = (unsigned char*)malloc(x);
memset(tab, 0x00, x);
LARGE_INTEGER b, f, e, r;
QueryPerformanceCounter(&b);
for (i=1; i<x; ++i)
{
if (tab[i])
continue;
if (GCD(x, i) == 1)
count++;
else
{
for (j=0, n=0; n<x; ++j)
{
n = i * j;
if (n<x)
tab[n] = 1;
}
}
}
QueryPerformanceFrequency(&f);
QueryPerformanceCounter(&e);
r.QuadPart = (e.QuadPart - b.QuadPart) * 1000 / f.QuadPart;
printf("%d\n", count);
printf("%lld小时%lld分%lld.%03lld秒\n", r.QuadPart / 3600000, (r.QuadPart / 60000) % 60, (r.QuadPart /1000) % 60, r.QuadPart % 1000);
free(tab);
getchar();
}
jackyjkchen 2012-10-05
  • 打赏
  • 举报
回复
我压根没用筛选,直接遍历,25608作为输入的话也是瞬间输出,大100倍的2560800也是秒级输出
,筛选法性能应该更快

另外如果你不是64位机器,别用我这个ULONG64,会降低性能的


#include <stdio.h>
#include <Windows.h>

inline BOOLEAN IsEven(ULONG64 x)
{
if (x & 0x01ULL)
return FALSE;
else
return TRUE;
}

ULONG64 GCD(ULONG64 x, ULONG64 y)
{
if (x < y)
return GCD(y, x);
if (y == 0)
return x;
else
{
if (IsEven(x))
{
if (IsEven(y))
return GCD(x>>1, y>>1) << 1;
else
return GCD(x>>1, y);
}
else
{
if (IsEven(y))
return GCD(x, y>>1);
else
return GCD(y, x-y);
}
}
}

int main()
{
const int x = 25608;
int i = 0, count = 0;
for (i=0; i<x; ++i)
{
if (GCD(x, i) == 1)
count++;
}
printf("%d\n", count);
getchar();
}
w602174096 2012-10-05
  • 打赏
  • 举报
回复
我的GCD算法是辗转相除法,应该是个很经典的算法了。。不过这个我可以试试,挺不错的!
jackyjkchen 2012-10-05
  • 打赏
  • 举报
回复
你是公约数算法本身耗时太长了吧,你的思路是个筛选法,应该很快的

这是编程之美上最大公约数算法


inline BOOLEAN IsEven(ULONG64 x)
{
if (x & 0x01ULL)
return FALSE;
else
return TRUE;
}

ULONG64 GCD(ULONG64 x, ULONG64 y)
{
if (x < y)
return GCD(y, x);
if (y == 0)
return x;
else
{
if (IsEven(x))
{
if (IsEven(y))
return GCD(x>>1, y>>1) << 1;
else
return GCD(x>>1, y);
}
else
{
if (IsEven(y))
return GCD(x, y>>1);
else
return GCD(y, x-y);
}
}
}

69,368

社区成员

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

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