[Project Euler]加入欧拉 Problem 12

The sequence of triangle numbers is generated by adding the natural numbers. So the 7^(th) triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:

1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

Let us list the factors of the first seven triangle numbers:

     1: 1
     3: 1,3
     6: 1,2,3,6
    10: 1,2,5,10
    15: 1,3,5,15
    21: 1,3,7,21
    28: 1,2,4,7,14,28

We can see that 28 is the first triangle number to have over five divisors.

What is the value of the first triangle number to have over five hundred divisors?

第一个拥有超过500个因子的三角数?

 

这个问题如果暴力求解的话,估计时间要很长的。没有几分钟应该是出不来的。

对于前面的三角数,这个应该很熟悉了,它就是 n * (n + 1) / 2;

现在关键问题就是如何将这个数分解,暴力的方法就是从1遍历到这个数,轮番除,计数。

 

数学里面有关于整数分解的理论:

整数分解

维基百科,自由的百科全书

跳转到: 导航, 搜索

数学中,整数分解(质因子分解)问题是指:给出一个正整数,将其写成几个素数的乘积。例如,给出45这个数,它可以分解成32 ×5。根据算术基本定理,这样的分解结果应该是独一无二的。这个问题在代数学密码学计算复杂性理论量子计算机等领域中有重要意义。

 

因子分解

完整的因子列表可以根据素数分解推导出,将幂从零不断增加直到等于这个数。例如,因为45= 32×51,45可以被30 ×50,30×51,31×50,31×51,32×50,和32×51,或者 1,5,3,9,15,和 45整除。相对应的,素数分解只包括素数因子。参见素数分解算法

 

有了上面的知识,这个题的解决方向应该就有了。

 

对n进行不断自加,找到一个数,里面的所有因子的指数加一 相乘大于500.比如上面的45,其实就是(2 + 1) * (1 + 1) = 6.

 

下面就是写代码了:

整个代码运行时间在3秒左右。还是可以接受. 里面也包含了暴力的方法,不过暴力求解,我的机器是没有运行出来。估计要很长时间吧。

 

写代码注意几点,

特别注意,在处理数组的时候,要注意数组的下标从0开始的,所以检测元素的时候,没有的话,要返回负数,这样比较好处理。前面由于没有注意到这个问题,调试了很久o(╯□╰)o

欧拉项目第十二题#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

int isContain(int arr[], int n, int num); //检测一个数组里面是否包含数num, 返回位置,如果不包含返回 -1 

double bruteDiv(int n);  // 暴力求解法 参数 最少多少个因子, 返回满足的数 

double mathDiv(int n); // 数论理论求解 参数 最少多少个因子, 返回满足的数 

int main(int argc, char *argv[])
{
    clock_t start_time=clock(); 
    double num1 = mathDiv(500);   
    clock_t end_time=clock(); 
    printf("%lf\n", num1);  
    printf("Running time is: %lf ms\n", (double)(end_time-start_time)/CLOCKS_PER_SEC*1000);
      
  system("PAUSE");	
  return 0;
}

double bruteDiv(int n)
{
    double sum = 1.0;
    int tmpn = 1;
    int nd = 0;
    
    while(nd <= n)
    {
        sum = tmpn * (tmpn + 1) / 2;        
        nd = 0;        
        double i;        
        for(i = 1; i <= sum; i++)
        {
            if(fmod(sum, i) == 0)
            {
                nd++;
            }
        }                
        tmpn++;        
    }
    
    return sum; 
}

double mathDiv(int n)
{
    double sum = 1.0, rsum;
    int tmpn = 1, nd = 1;
    int arr1[100], arr2[100]; // 估算可以分解为100个质数, arr1保存质数,arr2保存对应质数个数     
    
    while(nd <= n)
    {
        int i;        
        for(i = 0; i < 100; i++) //初始化数组 
        {
            arr1[i] = 0;
            arr2[i] = 1;
        }
        
        sum = tmpn * (tmpn + 1) / 2;
        rsum = sum;
        nd = 1;       
        
        int k = 2;        
        int j = 0;
        while(k <= sum) // 将数进行因素分解 
        {
            if(fmod(sum, k) == 0)
            {
                int index = isContain(arr1, 100, k);
                if(index == -1)  // 检测质数数组里是否有该因子
                {
                    arr1[j] = k;
                    arr2[j]++;
                    j++;                    
                }
                else
                {
                    arr2[index]++;
                }                
                sum = sum / k;
            }
            else
            k++;
        }
        
        int m = 0;
        while(arr2[m] != 1)
        {
            nd *= arr2[m];
            m++;    
        }        
        tmpn++;        
    }
    
    return rsum;
}

int isContain(int arr[], int n, int num)
{
    int i;
    for(i = 0; i < n; i++)
    {
        if(arr[i] == num)
        return i;
    }    
    return -1;
}

转载于:https://www.cnblogs.com/herbert/archive/2011/01/30/1947932.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值