λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

πŸ“š 전곡 곡뢀/μ•Œκ³ λ¦¬μ¦˜ 해석 및 섀계

[μ•Œκ³ λ¦¬μ¦˜] Greedy algorithm - μ΄μ§‘νŠΈ λ‚˜λˆ—μ…ˆ(cpp)

문제
μ΄μ§‘νŠΈ λ‚˜λˆ—μ…ˆμ„ ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.
μž…λ ₯
p/qλ₯Ό λ‚˜νƒ€λ‚΄λŠ” 두 μ •μˆ˜ p, qκ°€ 사이에 곡백을 ν•˜λ‚˜ 두고 주어진닀.
pλŠ” 1 이상 1,000 μ΄ν•˜, qλŠ” p+1 이상 2,000 μ΄ν•˜μΈ μ •μˆ˜
좜λ ₯
μˆ˜μ—… μ‹œκ°„μ— 배운 μ΄μ§‘νŠΈ λ‚˜λˆ—μ…ˆμ˜ 결과둜 λͺ‡ 개의 λΆ„μˆ˜κ°€ λ‚˜μ˜€λŠ”μ§€ 좜λ ₯ν•œλ‹€. 예λ₯Ό λ“€μ–΄, 5/6은 1/2 + 1/3μ΄λ―€λ‘œ 2개의 λΆ„μˆ˜κ°€ ν•„μš”ν•˜λ‹€.

예제 μž…λ ₯ 1
5 6
예제 좜λ ₯ 1
2
예제 μž…λ ₯ 2
19 20
예제 좜λ ₯ 2
4

μ•Œκ³ λ¦¬μ¦˜ μˆ˜μ—…μ˜ 첫 κ³Όμ œμ˜€λ‹€.

 

μ΄μ§‘νŠΈ λ‚˜λˆ—μ…ˆμ΄λž€, 유리수 p/qκ°€ 주어지면 λΆ„μžκ°€ 1인 λΆ„μˆ˜λ“€μ˜ ν•©μœΌλ‘œ p/qλ₯Ό ν‘œν˜„ν•˜λŠ” 것이닀.

예) 5/6 = 1/2 + 1/3 , 3/4 = 1/2 + 1/4

 

μš•μ‹¬μŸμ΄ 기법, ν”νžˆ Greedy μ•Œκ³ λ¦¬μ¦˜μ΄λΌκ³  λΆ€λ₯΄λŠ” 기법을 μ‚¬μš©ν•˜μ—¬ 풀이할 수 μžˆλ‹€.

 

μˆ˜μ—… μ‹œκ°„μ—λŠ” 두 κ°€μ§€μ˜ 해결법을 λ°°μ› λ‹€.

첫번째 방법이닀.

n= 2, 3, ... ν•΄λ³΄λ©΄μ„œ, 1/nκ³Ό p/q 쀑 μ–΄λŠ μˆ˜κ°€ 더 큰지 μƒκ°ν•΄λ³΄μž.
1/n이 더 크닀면 n:= n+1, μ•„λ‹ˆλ©΄ p/q = p/q - 1/n 으둜 계속 문제λ₯Ό ν’€μž. p/qκ°€ 0이 되면 μ’…λ£Œν•œλ‹€.

p/q = 5/6이면 1/2 < 5/6
5/6 - 1/2 = 2/6 = 1/3
p/q = 1/3이면 1/2 > 1/3. 1/3 <= 1/3.
p/q = 1/3 - 1/3 = 0 으둜 μ’…λ£Œ.

 

λ‹¨μˆœνžˆ ν•˜λ‚˜μ”© λΉ„κ΅ν•΄μ„œ μ—°μ‚°ν•˜λŠ” 방법이닀.

ν•˜μ§€λ§Œ μœ„ 방법은 λΆ„λͺ¨μ˜ 값이 컀질수둝 λΉ„νš¨μœ¨μ μ΄λ‹€. λΆ„λͺ¨κ°€ μ•„μ£Ό 큰 숫자라면, μ‹œκ°„λ„ μ•„μ£Ό 였래 걸릴 것이닀.

 

 

κ·Έλ ‡λ‹€λ©΄, 두 번째 방법을 μ‚΄νŽ΄λ³΄μž

주어진 수 p/q에 λŒ€ν•΄μ„œ, 이 수의 μ—­μˆ˜ q/p와 κ°™κ±°λ‚˜ 큰 κ°€μž₯ μž‘μ€ μ •μˆ˜ [q/p]λ₯Ό μ°Ύκ³ , 1/[q/p]λ₯Ό p/qμ—μ„œ λΊ€λ‹€.
이 과정을 0이 λ λ•ŒκΉŒμ§€ λ°˜λ³΅ν•œλ‹€.

5/6 에 λŒ€ν•΄μ„œ, [6/5] = 2.
5/6 - 1/2 = 1/3
1/3
에 λŒ€ν•΄μ„œ, [3/1] = 3. 1/3 - 1/3 = 0.

 

μ—­μˆ˜λ₯Ό ν™œμš©ν•œλ‹€λ©΄ 훨씬 λΉ λ₯΄κ³  효율적으둜 μ΄μ§‘νŠΈ λ‚˜λˆ—μ…ˆμ„ ν•  수 μžˆλ‹€.

λΆ„λͺ¨λ₯Ό 1μ”© μ¦κ°€μ‹œμΌœ μ—°μ‚°ν•˜λŠ” λŒ€μ‹ , μ—­μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 1/[q/p]에 λ°”λ‘œ μ ‘κ·Όν•  수 μžˆλ‹€λŠ” 차이가 μžˆλ‹€.

 

이 λ‘λ²ˆμ§Έ 방법을 μ‚¬μš©ν•˜μ—¬ 과제λ₯Ό ν•΄κ²°ν•˜μ˜€λ‹€.

#include <iostream>
#include <numeric>
using namespace std;

int main(){

    int p, q;
    int n = 1;
    int cnt = 0;
    cin >> p >> q; // p/q
    // if(p<1 || p>1000 || q<p || q>2000)

    while(p > 0){
        cnt++;
        while(1){ 
            if(n > q/p) break;
            n++;
        }
        p = p*n - q;
        q = q * n;
        int tmp = gcd(p, q);
        p /= tmp;
        q /= tmp;
        if(p == 1) { cnt++; break; }
    }
    cout << cnt;
    return 0;
}

 

κ²°κ³ΌλŠ” 만점!