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.
n | Relatively Prime | φ(n) | n/φ(n) |
---|---|---|---|
2 | 1 | 1 | 2 |
3 | 1,2 | 2 | 1.5 |
4 | 1,3 | 2 | 2 |
5 | 1,2,3,4 | 4 | 1.25 |
6 | 1,5 | 2 | 3 |
7 | 1,2,3,4,5,6 | 6 | 1.1666… |
8 | 1 ,3,5,7 | 4 | 2 |
9 | 1,2,4,5,7,8 | 6 | 1.5 |
10 | 1,3,7,9 | 4 | 2.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) |
---|---|---|---|
2 | 1 | 1 | 2 |
3 | 1,2 | 2 | 1.5 |
4 | 1,3 | 2 | 2 |
5 | 1,2,3,4 | 4 | 1.25 |
6 | 1,5 | 2 | 3 |
7 | 1,2,3,4,5,6 | 6 | 1.1666… |
8 | 1 ,3,5,7 | 4 | 2 |
9 | 1,2,4,5,7,8 | 6 | 1.5 |
10 | 1,3,7,9 | 4 | 2.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()