算法进化历程之相亲数

巧若拙(欢迎转载,但请注明出处:http://blog.csdn.net/qiaoruozhuo

题目来自于编程论坛“吴健飞飞”的提问:求4位数以内的相亲数对

2500年前数学大师毕达哥拉斯发现,220与284两数之间存在下列奇妙的联系:

220的真因数之和为1+2+4+5+10+11+20+22+44+55+110=284

284的真因数之和为1+2+4+71+142=220

毕达哥拉斯把这样的数对a,b称为相亲数:a的真因数(小于本身的因数)之和为b,而b的真因数之和为a。

版主rjsp给出了两个精妙的算法,我对其进行了整理,作出此文。对为此文提供灵感的网友表示感谢。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>

void AmicablePair_1(int n);//求相亲数的原始方法
void AmicablePair_2(int n);//以空间换时间
void AmicablePair_3(int n);//用加法运算代替求余运算,更加高效 

int main(void)
{
    unsigned n = 1000000;

    clock_t begin, end;
    double  cost;
    begin = clock();

	AmicablePair_1(n);//求相亲数的原始方法 

    end = clock();
    cost = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("%lf seconds\n", cost);

    begin = clock();

	AmicablePair_2(n);//求相亲数的原始方法 

    end = clock();
    cost = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("%lf seconds\n", cost);

    begin = clock();

	AmicablePair_3(n);//求相亲数的原始方法 

    end = clock();
    cost = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("%lf seconds\n", cost);

    return 0;
}

void AmicablePair_1(int n)//求相亲数的原始方法
{
	unsigned i, j, sa, sb;

	for (i=2; i<=n; i++)
    {
        sa = 1;
        for (j=sqrt(i); j>1; j--)//计算i的真因数和
        {
            if (i % j == 0)
                sa += j + i / j;
        }
        if (sa <= i)//确sa>i,以避免重复计算
            continue;
        sb = 1;
        for (j=sqrt(sa); j>1 && sb<=i; j--)//计算sa的真因数和
        {
            if (sa % j == 0)
                sb += j + sa / j;
        }
        if (sb == i)
            printf( "%u\t%u\n", i, sa);
    }
}

void AmicablePair_2(int n)//以空间换时间
{
	unsigned i, j;
	int *p = (unsigned*)malloc(sizeof(unsigned)*(n+1));

	if( !p )
    {
		printf("Out of space!");
		exit(0);
	}

	for (i=2; i<=n; i++)
    {
        p[i] = 1;
        for (j=sqrt(i); j>1; j--)//计算i的真因数和,并存储在p[i]中
        {
            if (i % j == 0)
                p[i] += j + i / j;
            if (p[i] > n)
            {
                p[i] = 0;
                break;
            }
        }
    }

    for (i=2; i<=n; i++)
    {
        if (p[p[i]] == i && i < p[i]) //相亲数对
            printf( "%u\t%u\n", i, p[i]);
    }

    free(p);
} 

void AmicablePair_3(int n)//用加法运算代替求余运算,更加高效
{
	unsigned i, j, mid;
	int *p = (unsigned*)malloc(sizeof(unsigned)*(n+1));

	if( !p )
    {
		printf("Out of space!");
		exit(0);
	}

	mid = n / 2;
    for (i=1; i<=mid; i++)
    {
        for (j=i*2; j<=n; j+=i)//因为j是i的倍数,故i之和即j的真因数和
        {
            p[j] += i;
        }
    }

    for (i=2; i<n; i++)
    {
        if (p[i] <= n && p[p[i]] == i && i < p[i]) //相亲数对
            printf( "%u\t%u\n", i, p[i]);
    }

    free(p);
} 
时间: 2024-08-01 17:54:37

算法进化历程之相亲数的相关文章

算法进化历程之“根据二叉树的先序和中序序列输出后序序列”

巧若拙(欢迎转载,但请注明出处:http://blog.csdn.net/qiaoruozhuo) 前不久在看到一个作业"根据二叉树的先序和中序序列输出后序序列",当时我参考<数据结构与算法(C语言)习题集>上的做法,先根据先中序序列确定一颗二叉树,然后后序遍历二叉树输出后序序列. 函数采用了递归算法,利用函数传入的先序和中序序列的左右边界,确定要处理的序列段,生成相应的二叉树. 基本思路是,把该段先序序列的第一个元素作为当前二叉树的根结点,然后在中序序列找到根结点.根结点

相亲数--Python

想亲数:在遥远的古代,人们发现某些自然数之间有特殊的关系:如果两个数a和b,a的所有除本身以外的因数之和等于b,b的所有除本身以外的因数之和等于a,则称a,b是一对相亲数 code: 1 def sumFunc(n): #这个是求真因数的和,真因数不包括自己 2 a = 1 3 b = n 4 sum = 0 5 while a < b: 6 if n % a == 0: 7 sum += (a + b) 8 a += 1 9 b = n / a 10 if a == b and n % a =

以太网进化历程半景-从10Mbps到1Tbps

继Netfilter conntrack,Linux Bridge之后又是一个半景,依然如故,我不会在文中罗列技术规范和细节,仅仅是希望本文可以帮助人们理解以太网到底是什么,为什么如此成功. 0.动机,愿景以及声明 前端时间帮朋友解决一个编码问题,碰到了全双工这个概念,正好写了一个程序,实现了类似CDMA那种沃尔什编码,即从一个混合信号中分离中自己要的那部分,然而代码是好写的,往线缆上一放就全乱了,这是电学原理导致的.就这么说吧,请看下图: 请问P点的电压是多少?很简单的一个问题,是不是?是的.

1144: 零起点学算法51——数组中删数

1144: 零起点学算法51--数组中删数 Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitted: 3304  Accepted: 933[Submit][Status][Web Board] Description 在给定的数组中删除一个数 Input 多组测试,每组第一行输入1个整数n(n<20),然后是n个整数 第二行输入1个整数m Output 删除在第一行的n个整数中第一次出现数字m并删除,然后按

1145: 零起点学算法52——数组中删数II (有问题!)

1145: 零起点学算法52--数组中删数II Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitted: 2935  Accepted: 793[Submit][Status][Web Board] Description 在给定的数组中删除数 Input 多组测试,每组第一行输入1个整数n(n<20),然后是n个整数 第二行输入1个整数m Output 删除在第一行的n个整数中的数字m(多个的话都要删除),

算法15---数论2---亲密数

算法16---数论2---亲密数 如果整数a的因子和等于整数b,整数b的因子和等于整数a,因子包括1但不包括本身,且a不等于b,则称a和b为亲密数对. 1 /* 2 题目:亲密数 3 author taoliu——alex 2016.10 4 5 主要实现两种 6 1 判断两个数是不是亲密数. 7 2 找出一定范围内的亲密数. 8 9 */ 10 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 15 int friendnum(

算法15---数论4---自守数

算法15---数论4---自守数 如果一个正整数的平方的末尾几位数等于这个数本身,那么这个数便称为自守数. 自守数有如下的一些性质 (1) 以自守数为后几位的两数相乘,结果的后几位仍是自守数: (2) n+1位的自守数出自n为的自守数. (3) 两个n位子守数的和等于10的n次方加1. 我们给出两种自守数的算法 1 /* 2 题目:自守数 3 author taoliu——alex 2016.10 4 5 主要实现: 6 判断自守数: 7 8 */ 9 10 11 #include <stdio

相亲数

程序地址:http://www.cheemoedu.com/exercise/14 问题描述: 220的真因数之和为1+2+4+5+10+11+20+22+44+55+110=284284的真因数之和为1+2+4+71+142=220毕达哥拉斯把这样的数对A.B称为相亲数:A的真因数之和为B,而B的真因数之和为A.求100000以内的相亲数. 我的代码: def perfect(n):     a=1     b=n     s=0     while a<b:         if n%a==

算法笔记_135:格子取数问题(Java)

目录 1 问题描述 2 解决方案   1 问题描述 有n*n个格子,每个格子里有正数或者0,从最左上角往最右下角走,只能向下和向右走,一共走两次(即从左上角往右下角走两趟),把所有经过的格子里的数加起来,求总和的最大值.如果两次经过同一个格子,则最后求得的总和中该格子中的数只加一次. 2 解决方案 此处采用动态规划法,可以较大的提高时间效率. 具体代码如下: package com.liuzhen.practice; import java.util.Scanner; public class