题目:
实现100000以内的相亲数对输出
相亲数:除自身以外的约数和,比如:220:1+2+4+5+10+11+20+22+44+55+110=284,284:1+2+4+71+142=220,所以220和284构成相亲数对。
输出格式:从小到大每行一对相亲数对,中间一个空格隔开。
看到这个题目,第一个朴素的想法就是让计算机循环计算啊!事实证明,朴素的想法是最原始的,也是最慢的,10万以内还可以接受,100万以上就呵呵了!
算法一:慢的很
/*功能:求解相亲数
说明:最朴素的解法,也是最耗时的
*/
#include <stdio.h>
#include <time.h>
/*
功能:求正整数n的因子和
参数:n(一个正整数)
返回:n的所有因子和(除自身外所有的约数)
*/
unsigned int factorsSum(unsigned int n)
{
unsigned int i, sum=0;
for(i=1; i<n; i++)
if(n%i == 0)
sum += i;
return sum;
}
#define MAX_N 100000
int main(int argc, char *argv[])
{
double startTime,endTime;//开始时间,结束时间
unsigned int numberFactorsSum[MAX_N], i, j;
startTime=(double)clock();
// 求 1~(MAX_N-1) 之间每个数的真因数之和
for(i=1; i<MAX_N; i++)
numberFactorsSum[i] = factorsSum(i);
for(i=1; i<MAX_N; i++)
for(j=i+1; j<MAX_N; j++)
// 根据亲合数的定义dao,判定 i 和 j 是不是亲合数
if(numberFactorsSum[i] == j && numberFactorsSum[j] == i)
printf("%d %d\n", i, j);
endTime=(double)clock();
printf("Total Run Time:%f\n",endTime-startTime);//linux下返回的是纳秒,windows下是毫秒
return 0;
}
算法二:这是已知网络上最快的算法
/*计算相亲数的快速算法
*/
#include <stdio.h>
#include <time.h>
#define MAX_TEST 100000
long nTable[MAX_TEST];//素数表
char nFlag[MAX_TEST];
//构造未标记用于降低内存使用
void printConsole()
{
for(long i=2;i<MAX_TEST;i++)
{
if(nFlag[i]==0)
{
if(nTable[i]<MAX_TEST&&(nTable[nTable[i]+1]+1==i))
printf("%ld\t%ld\n",i,nTable[i]+1);
nFlag[nTable[i]+1]=1;
}
}
}
int main()
{
long j=0;
double startTime,endTime;
startTime=(double)clock();
for(long i=2;i<MAX_TEST;i++)
{
j=(i<<1);
while(j<MAX_TEST)
{
nTable[j]+=i;
j+=i;
}
}
endTime=(double)clock();
printConsole();
printf("Total Run Time:%f\n",endTime-startTime);
//printf("数值:%ld\n",nTable[220]);
return 1;
}
算法三:这是网上使用C#的算法,还没有改造,有时间改造为c
/*
参考资料:https://www.cnblogs.com/devil0153/archive/2010/08/23/AmicablePair-And-PerfectNumber-SP2.html(使用本方法)
https://www.cr173.com/html/6390_all.html(未采用)
简单说一下概念,相亲数是指两个正整数中,彼此的全部约数之和(本身除外)与另一方相等。举例来说:
220的全部约数(除掉本身)相加是:1+2+4+5+10+11+20+22+44+55+110=284
284的全部约数(除掉本身)相加的和是:1+2+4+71+142=220
所以220和284就是一对相亲数。
那什么是完全数呢?即它所有的真因子(即除了自身以外的约数)的和恰好等于它本身。例如:
第一个完全数是6,它有约数1、2、3、6,除去它本身6外,其余3个数相加,1+2+3=6
第二个完全数是28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4+7+14=28
*/
/// <summary>
/// 部分分解不求和的空间算法
/// </summary>
public class Algorithm6
{
public List<int> primeList = new List<int>();
public int[] firstFactorList;
public int[] remainingList;
public int[] resultList;
public int GetNextFactor(int num)
{
var max = (int)Math.Sqrt(num);
for (int i = 0; i < primeList.Count; i++)
{
var p = primeList[i];
if (p > max) break;
if (num % p == 0)
return p;
}
primeList.Add(num);
return num;
}
public int GetSum(int num)
{
var factor = firstFactorList[num] = GetNextFactor(num);
if (factor == num)
{
remainingList[num] = 1;
return 1;
}
else
{
remainingList[num] = num / firstFactorList[num];
var r = remainingList[num];
while (r % factor == 0)
r = r / factor;
return (resultList[remainingList[num]] + remainingList[num]) * factor + (resultList[r] + r) - num;
}
}
public void Run(int limit)
{
firstFactorList = new int[limit];
remainingList = new int[limit];
resultList = new int[limit];
int perfertCount = 0;
int amicablePairCount = 0;
for (var num = 2; num < limit; num++)
{
var result = resultList[num] = this.GetSum(num);
if (result == num)
{
Console.WriteLine("{0}是完全数", num);
perfertCount++;
}
else if (result < num && resultList[result] == num)
{
Console.WriteLine("{0}和{1}是一对相亲数", result, num);
amicablePairCount++;
}
}
Console.WriteLine("在{0}到{1}中至少有{2}个完全数和{3}对相亲数", 2, limit, perfertCount, amicablePairCount);
}
}