예를 들자면, 2의 5승만큼의 약수를 가지는 최소수를 찾기 위해서는, 서로 다른 소수가 가 있을 때, 다음과 같은 경우에 2의 5승만큼의 약수를 가집니다.
이 답을 풀기 위해서 다음과 같이 했습니다.
d : 약수 갯수의 승수.
GetMinNumber( d )
F <- {}
while( d > 0 )
c <- minimum element of P
if F = {} or c < minimum elemement of F then
F <- { (c, c) } U F
P <- P - c
else
r <- minimum element of F
F <- F - r
F <- { ( r.x*r.x*r.y, r.y ) } U F
d <- d - 1
result <- 1
for each c in F
result <- result * c.x
이런 알고리즘을 가지면, 우리는 최소의 수를 구할 수 있습니다.
2의 5승 약수갯수를 가지는 수를 찾는다면,
F 는 현재 비어있으므로 가장 작은 소수 2를 넣습니다.
F : (2, 2)
그 다음 소수는 3이므로, 3과 2x2와 비교합니다. 3이 작으므로 3을 넣습니다.
F : (2, 2) (3, 3)
그 다음 소수는 5이므로, 5와 2x2와 비교합니다. 2x2가 작으므로, (2x2x2, 2)를 (2, 2) 대신 넣습니다.
F : (3, 3) (8, 2)
역시 그 다음 소수는 5이므로 5와 3x3을 비교합니다. 5가 작으므로 5를 넣습니다.
F : (3, 3) (8, 2) (5, 5)
다음 소수는 7이므로 7과 3x3을 비교합니다. 7이 작으므로 7을 넣으면,
F : (3, 3) (8, 2) (5, 5) (7, 7)
이 되어서 F의 모든 원소들의 첫번째 값을 곱하면,
3x8x5x7 = 840
이 되어, 840이 최소값이 됩니다.
이것을 프로그램적으로 기술하기 위해서 삽입정렬을 사용했습니다. 아마도 힙을 사용했으면 더 빠른 시간안에 답을 찾을 수 있었겠더라고요.
소스는 다음과 같습니다.
#include <stdio.h> #include <stdint.h> #include <stdlib.h> #define DIV 500500507 #define TDIVS 500500 struct Factor { uint64_t value; uint32_t prime; uint32_t power; }; bool IsPrime(uint64_t n); void Insert(uint32_t k); bool CheckAndSquareMove(uint32_t k); Factor factors[TDIVS]; int pfactors = 0; int main() { uint32_t cp = 3; int cpp = 1; Insert(2); int pvalue = TDIVS - 1; while( pvalue-- > 0 ) { if( !CheckAndSquareMove(cp) ) { Insert(cp); for( cp += 2 ; !IsPrime(cp) ; cp += 2 ) ; } } uint64_t ans = 1; for( int i = 0 ; i < pfactors ; i++ ) { ans *= (factors[i].value%DIV); ans %= DIV; } printf("ans = %jd\n", ans); } void Insert(uint32_t k) { int last = pfactors++ - 1; uint64_t v = k; v *= k; while( last >= 0 && v < factors[last].value*factors[last].prime ) { factors[last+1] = factors[last]; last--; } factors[last+1].value = k; factors[last+1].prime = k; factors[last+1].power = 1; } bool CheckAndSquareMove(uint32_t k) { uint64_t value = factors[0].value * factors[0].prime; if( value > k ) return false; Factor t; t.value = factors[0].value * value; t.prime = factors[0].prime; t.power = factors[0].power+1; int last = 1; while( last < pfactors && t.value*t.prime > factors[last].value*factors[last].prime ) { factors[last-1] = factors[last]; last++; } factors[last-1] = t; return true; }
아울러 여기서 소수를 찾기 위해서 소수인지 검사하는 것은 밀러 라빈 방법을 사용하였습니다.
'Programming > Project Euler' 카테고리의 다른 글
26. 프로젝트 오일러 #26 : 순환고리 (0) | 2015.02.27 |
---|---|
25. 프로젝트 오일러 #25 : 1000자리 피보나치 수열항 구하기 (0) | 2015.02.17 |
501. 프로젝트 오일러 #501 : 약수의 갯수가 8개인 수 찾기 (0) | 2015.02.06 |
24. 프로젝트 오일러 #24 : 백만번째 순열 수 구하기 (0) | 2015.01.27 |
23. 프로젝트 오일러 #23 : 초과수의 합으로 표현 안되는 자연수들의 합 (0) | 2015.01.26 |
댓글