$$\newcommand{\Z}{\mathbb{Z}} \newcommand{\R}{\mathbb{R}} \newcommand{\Q}{\mathbb{Q}} \newcommand{\N}{\mathbb{N}}\newcommand{\C}{\mathbb{C}} \newcommand{\oiv}[1]{\left] #1 \right[} \newcommand{\civ}[1]{\left[ #1 \right]} \newcommand{\ad}[1]{\text{ad}(#1)} \newcommand{\acc}[1]{\text{acc}(#1)} \newcommand{\Setcond}[2]{ \left\{\, #1 \mid #2 \, \right\}} \newcommand{\Set}[1]{ \left\{ #1 \right\}} \newcommand{\abs}[1]{ \left\lvert #1 \right\rvert}\newcommand{\norm}[1]{ \left\| #1 \right\|}\newcommand{\prt}{\mathcal{P}}\newcommand{\st}{\text{ such that }}\newcommand{\for}{\text{ for }} \newcommand{\cl}[1]{\text{cl}(#1)}\newcommand{\oiv}[1]{\left] #1 \right[}\newcommand{\interior}[1]{\text{int}(#1)}$$

Project Euler 포스팅 시작 + Problem 75::::Gratus' Blog

Project Euler 포스팅 시작 + Problem 75

알고리즘 문제풀이/Project Euler 2019. 5. 28. 13:30

Project Euler 는 수학 계열의 고난도 알고리즘 (사실 알고리즘이랑 크게 상관 없는 문제도 있지만) 문제들을 연습할 수 있는 나름 좋은 문제 소스이다.

 

문제 유형이 PS랑 약간 다른데, 이런 식이다.

PS (백준, Codeforces 등) : 1초 내에 $N$ 이하의 소수를 전부 찾는 코드를 짜라. $N \leq 100,000$.

Project Euler (PE라고 줄이자) : 10만 1번째 소수는?

 

어쨌든 프로그래밍을 이용해서 해결하는 문제긴 하다. 

 

난이도는 %로 표시되는데,

5%~10%문제 : 단순 구현 문제 (에라토스테네스의 체 구현 같은거), 적당한 생각으로 풀 수 있는 문제들이 있다.

15%~ : 펜과 종이를 꽤 많이 써야 하는 문제가 나오기 시작한다.

25%~ : 수식을 잘 정리하거나, 수학적인 정리를 알아야 하는 문제들이 나온다.

35%~ : 지금 현재 내 실력으로 풀 수 있는 한계가 30~35% 정도 되는것 같은데, 꽤 오랜 시간 점화식을 생각한 후에도 줄여야 하는 문제 등등이 있었다.

 

1 minute rule 이라고, 코드는 "1분 이내에 돌아가는 것" 이 대략적인 기준이다. 물론 엄격한 것은 아니고, 무엇보다 사이트는 답만 요구하니까 사실 오래 걸려도 상관 없다. 정해가 그게 아니라는 것일 뿐... 언어마다 다른데, 아마 C 기준인 듯? 하지만 나는 Bigint를 짜고 싶지도 않고(...) Python 라이브러리가 유용하기 때문에 Python 등으로도 많이 풀 듯 하다.


Problem 75. Singular Integer Right Triangles

문제 링크

 

스포방지선


 

 

 

 

 

 


$1,500,000$ 이하의 정수들 중, 정확히 1개의 $a < b < c$ 가 존재해서, $a^2 + b^2 = c^2$, $a+b+c = L$ 을 만족하는 $L$의 개수를 세는 문제이다. 

직각삼각형의 세 변의 길이가 되는 피타고라스 순서쌍 (또는 피타고라스 삼조 라고 부른다) 에는 좋은 성질이 있다.

원시 피타고라스 삼조 라고 부르는데, 어떤 자연수 $(a, b, c)$ 가 피타고라스 삼조이면 임의의 자연수 $n$ 에 대하여 $(na, nb, nc)$ 도 피타고라스 삼조이며, 그 역도 성립한다는 것이다. 즉, 모든 피타고라스 삼조는 어떤 원시 피타고라스 삼조의 자연수배라는 것이다.

 

또한, Euclid Formula 라 하여, 다음의 성질이 성립한다.

$m > n > 0$ 일 때, $a = m^2 - n^2,\ b = 2mn,\ c = m^2 + n^2$ 는 피타고라스 삼조를 이룬다. 

특히, $m$과 $n$의 홀짝성이 다르고, $gcd(m, n)$ 이 1일 때 (즉, $m$, $n$ 이 서로소일 때) 위 공식은 원시 피타고라스 삼조를 생성한다. 이 명제의 증명은 나중에 따로 쓰기로 하자. (상당히 귀찮은 요소가 많다)

 

이제, 적당히 생각을 해보자. 어차피 $c = m^2 + n^2 < \frac{L}{2}$ 여야 하므로

$m < \sqrt{\frac{L}{2}}$ 까지의 $m$과 그보다 작은 $n$ 만 보면 충분하다.

어떤 $m_0, n_0$ 에 대하여, 원시 피타고라스 삼조가 생성된다면 (즉, 위에서 기술한 조건을 만족한다면), 이 생성된 원시 피타고라스 삼조를 $a, b, c$라고 하고, $a+b+c = t$ 라고 하자. 이때, $t$의 배수들은 모두 $nt = na+nb+nc$ 이므로 원시가 아닌 피타고라스 삼조의 합이 된다. chk[n*t]++를 쭉 돌면서 해주자.

 

이런 식으로, $m, n$ 으로부터 생성된 모든 원시 피타고라스 삼조들의 배수들을 모두 마킹하고 나면, 1부터 1,500,000 까지 돌면서 chk배열의 값이 1인 것들의 수를 세면 끝.

 

많아야 $m^2$ 의 몇 배 정도를 돌게 되며, $m^2 = 750,000$ 이므로 이 값은 매우 빠르게 계산될 것이다.

 

 

코드

#include <bits/stdc++.h>
#pragma GCC optimize ("O3")
#pragma GCC optimize ("Ofast")
#define ll long long
#define gcd(A,B) (__gcd(A,B))
using namespace std;

const ll M = 1500000;
int chk[M+1];
int main()
{
    int max_m = (int)sqrt(750000);
    for (int m = 2; m<max_m; m++)
    {
        for (int n = 1; n<m; n++)
        {
            if ((m+n)%2 && (gcd(m,n)==1))
            {
                ll a = (ll)m*m-(ll)n*n;
                ll b = 2*(ll)m*n;
                ll c = (ll)m*m+(ll)n*n;
                ll tr = a+b+c;
                for (int i = 1; i*tr<=M; i++)
                    chk[i*tr]++;
            }
        }
    }
    int ans = 0;
    for (int i = 1; i<=M; i++)
        ans += (chk[i]==1?1:0);
    cout << ans << '\n';
}

Execution Time : 17ms

'알고리즘 문제풀이 > Project Euler' 카테고리의 다른 글

Project Euler Problem 577  (0) 2019.08.18
Project Euler Problem 587  (0) 2019.06.19
admin