Quantcast
Channel: YGC » ComputerScience
Viewing all articles
Browse latest Browse all 27

project euler -- problem 70

$
0
0

Euler's Totient function, φ(n) [sometimes called the phi function], is used to determine the number of positive numbers less than or equal to 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.
The number 1 is considered to be relatively prime to every positive number, so φ(1)=1.

Interestingly, φ(87109)=79180, and it can be seen that 87109 is a permutation of 79180.

Find the value of n, 1 < n < 107, for which φ(n) is a permutation of n and the ratio n/φ(n) produces a minimum.

I think this problem is very simple at first. Calculating φ(n) and if it's a permutation of n, then calculate n/φ(n), and iterating this procedure through 1 to N=1e7. By recording the minimal n/φ(n) ratio and the corresponding n, we can get the result easily. But N=1e7 is very large, and requires many time to run. Here, I use a property of totient function, that is φ(mn)=φ(m)*φ(n) if m and n are relatively prime, and cache the φ(n) which was calculated previously.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include<iostream>
#include<cmath>
#include<vector>
#include<limits>
 
using namespace std;
 
const int N=1e7;
 
bool isPerm(int x, int y);
int totient(int n);
 
int main() {
  double minRatio = std::numeric_limits<double>::max();
  int res = 0;
  for (int n = 2; n < N; n++) {
    int p = totient(n);
    if (isPerm(n, p)) {
      double ratio = (double)n/p;
      if (ratio < minRatio) {
	minRatio = ratio;
	res = n;
      }
    }
  }
  cout << "Answers of PE 70: " << res << endl;
  return 0;
}
 
int totient(int n) {
  static int phis[N] = {0, 1, 1};
  if (phis[n] != 0) {
    return(phis[n]);
  }
  for (int p=2; p <= sqrt(n); p++) {
    if ( n % p == 0 ) {
      int pk = p;
      while ( (n % (pk * p) == 0) ) {
	pk *= p;
      }
      if ( pk == n ) {
	// phis[n] = p^k
	phis[n] = n - n/p;
	return phis[n];
      }
      if ( phis[pk] == 0 ) {
	phis[pk] = pk - pk/p;
      }
      phis[n] = totient(pk) * totient(n/pk);
      return phis[n];
    }
  }
  phis[n] = n-1;
  return phis[n];
}
 
bool isPerm(int x, int y) {
  vector<int> xv, yv;
  while ( x > 10 ) {
    xv.push_back(x % 10);
    x /= 10;
  }
  xv.push_back(x);
 
  while ( y > 10 ) {
    yv.push_back(y % 10);
    y /= 10;
  }
  yv.push_back(y);
 
  if (xv.size() != yv.size())
    return false;
 
  sort(xv.begin(), xv.end());
  sort(yv.begin(), yv.end());
 
  for (int i=0; i<xv.size(); i++) {
    if (xv[i] != yv[i])
      return false;
  }
  return true;
}

The idea of this code is brute-force. By caching the φ(n), the running time is acceptable, it took less than 2 mins to get the correct answer.

$ date(); ./pe70; date()
Wed Dec 19 17:28:29 2012
Answers of PE 70: 8319823
Wed Dec 19 17:29:51 2012

Related Posts


Viewing all articles
Browse latest Browse all 27

Trending Articles