Project Euler Problem 69 (C++和Python代码实现和解析)

100 篇文章 3 订阅
87 篇文章 1 订阅

Problem 69 : Totient maximum

Euler’s Totient function, φ(n) [sometimes called the phi function], is used to determine the number of numbers less than n which are relatively prime to n. For example, as 1, 2, 4, 5, 7, and 8, are all less than nine and relatively prime to nine, φ(9)=6.

nRelatively Primeφ(n)n/φ(n)
2112
31,221.5
41,322
51,2,3,441.25
61,523
71,2,3,4,5,661.1666…
81 ,3,5,742
91,2,4,5,7,861.5
101,3,7,942.5

It can be seen that n=6 produces a maximum n/φ(n) for n ≤ 10.

Find the value of n ≤ 1,000,000 for which n/φ(n) is a maximum.

1. 欧拉项目第69题 : 欧拉函数的最大值

欧拉函数φ(n) (有时称为Phi函数), 用于确定小于n且与n互质的数的个数。例如:小于9 且与9互质的数有1, 2, 4, 5, 7, 和 8, 所以 φ(9)=6。

数n与n互质的数φ(n)n/φ(n)
2112
31,221.5
41,322
51,2,3,441.25
61,523
71,2,3,4,5,661.1666…
81 ,3,5,742
91,2,4,5,7,861.5
101,3,7,942.5

可以看到对于所有的小于等于10的n来说, 当n=6时,n/φ(n) 值最大。

对于不大于一百万的数n, 当n是多少时, n/φ(n) 值最大呢?

2. 求解分析

可以仔细阅读解决方案:[Find the number that maximises n/ϕ(n)]
(https://projecteuler.net/overview=069)

主要思路就是找到质因数最多的数n, 那么 n/φ(n) 值会最大。

3. C++ 代码实现

根据求解分析里的解决方案,我们使用了两个函数:createPrimeSieve()用质数筛子来创建一个质数筛子,calculatePhi()用来计算n的phi 值。

事实上,我们也可以不必用质数筛子函数createPrimeSieve() ,然后再找到合适的质因数集合primeFactors_s,C++11可以直接从primes_vec 创建一个合适的质因数集合primeFactors_s:

	vector<int> primes_vec = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 }; 

C++代码 (如果编译器支持C++11, 可以打开编译开关 CPP_11)

#include <iostream>
#include <set>
#include <vector>
#include <iterator>
#include <cmath>

using namespace std;

#define CPP_11

class PE0069
{
private:
    static const int m_max_n = 1000000; // one million
    bool  *m_primeSieve;                // prime Sieve
    void createPrimeSieve();

    double calculatePhi(int n, set<int>& primeFactors_s);

public:
#ifndef CPP_11
    PE0069() { m_primeSieve = new bool[m_max_n + 1]; createPrimeSieve(); }
    ~PE0069() { delete[] m_primeSieve; }
#endif
    int getTotientMaximum();
};

// create a prime Sieve of Eratosthenes below max value
void PE0069::createPrimeSieve()
{
    memset(m_primeSieve, true, (m_max_n + 1) * sizeof(bool));

    m_primeSieve[0] = m_primeSieve[1] = false;

    for (int i = 2; i <= (int)sqrt((double)m_max_n); i++)
    {
        if (true == m_primeSieve[i])
        {
            for (int j = i * i; j < m_max_n; j += i)
            {
                m_primeSieve[j] = false;
            }
        }
    }
}

double PE0069::calculatePhi(int n, set<int>& primeFactors_s)
{
    set<int>::iterator iter = primeFactors_s.begin();
    double p;
    double phi = n;

    while (iter != primeFactors_s.end())
    {
        p    = *iter;
        phi *= (p - 1) / p;
        iter++;
    }

    return phi;
}

int PE0069::getTotientMaximum()
{
    int product = 1;
    set<int> primeFactors_s;

#ifdef CPP_11
    vector<int> primes_vec = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };

    for (auto p : primes_vec)
    {
        if (product*p < m_max_n)
        {
            product *= p;
            primeFactors_s.insert(p);
        }
        else
        {
            break;
        }
    }
#else
    for (int n = 2; n <= m_max_n; n++)
    {
        if (true == m_primeSieve[n])
        {
            if (product*n < m_max_n)
            {
                product *= n;
                primeFactors_s.insert(n);
            }
            else
            {
                break;
            }
        }
    }
#endif

    double phi = calculatePhi(product, primeFactors_s);
    double max_n_div_phi = (product*1.0) / phi;

    cout << "For n<=1,000,000, when n=" << product << ", φ(n)=" << phi;
    cout << ", n/φ(n) is a maximum (" << max_n_div_phi << ")." << endl;

    return 0;
}

int main()
{
    PE0069 pe0069;

    pe0069.getTotientMaximum();

    return 0;
}     

4. Python 代码实现

我们使用了两个函数:createPrimeSieve()用质数筛子来创建一个质数列表,calculatePhi()用来计算n的phi 值。

事实上,我们也可以不用创建完整的质数列表,简化直接使用一个质数列表:

	primes_list = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ]

Python 代码

def createPrimeSieve(n):
    """ create prime sieve """
    sieve = [True] * n
    sieve[0] = sieve[1] = False

    for i in range(2, int(n**0.5)+1):
        if True == sieve[i]:
            for j in range(i*i, n, i):
                sieve[j] = False

    return [ i for i in range(1, n) if True==sieve[i] ]

def calculatePhi(n, primeFactors_list):
    """ calculate phi = n*phi*(1-1/p)  for p in primeFactors_list """
    phi = n
    for p in primeFactors_list:
        phi *= (p-1)/p
    return phi
    
def getTotientMaximum():
    max_n, product, primeFactors_list = 10**6, 1, []

    #primes_list = createPrimeSieve(max_n)
    primes_list = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ]

    for p in primes_list:
        if product*p < max_n:
            product *= p
            primeFactors_list += [ p ]
        else:
            break

    phi = calculatePhi(product, primeFactors_list)
    max_n_div_phi = product / phi

    print("For n<=1,000,000, when n=%d, φ(n)=%d, n/φ(n) is a maximum (%f)."
          %(product, phi, max_n_div_phi))

def main():
    getTotientMaximum()
    
if  __name__ == '__main__':
    main()
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值