본문 바로가기
Algorithm/BOJ

[BOJ]2193번: 이친수(java, c++)

by HBGB 2019. 10. 17.

https://www.acmicpc.net/problem/2193

 

2193번: 이친수

0과 1로만 이루어진 수를 이진수라 한다. 이러한 이진수 중 특별한 성질을 갖는 것들이 있는데, 이들을 이친수(pinary number)라 한다. 이친수는 다음의 성질을 만족한다. 이친수는 0으로 시작하지 않는다. 이친수에서는 1이 두 번 연속으로 나타나지 않는다. 즉, 11을 부분 문자열로 갖지 않는다. 예를 들면 1, 10, 100, 101, 1000, 1001 등이 이친수가 된다. 하지만 0010101이나 101101은 각각 1, 2번 규칙에 위배되

www.acmicpc.net

 

방법 1: Top-down

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
import java.io.*;
 
public class Main {
 
    public static long[] arrPinary;
    public static void main(String[] args) {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
            int iLength = Integer.parseInt(br.readLine());
            
            arrPinary = new long [iLength + 1];
            
            System.out.println(calculate(iLength));
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static long calculate (int length) {
        
        if(length <= 1 ) {
            return length;
        }
        
        if (arrPinary[length> 0) {
            return arrPinary[length];
        }
        
        arrPinary[length= calculate(length - 1+ calculate(length - 2);
        
        return arrPinary[length];
    }
}
Colored by Color Scripter

 

방법 2: Bottom-up

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
import java.io.*;
 
public class Main {
 
    public static void main(String[] args) {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
            int iLength = Integer.parseInt(br.readLine());
            
            long[] arrPinary = new long [iLength + 1];
            
            arrPinary[1= 1;
            
            for (int i = 2; i <= iLength; i++) {
                arrPinary[i] = arrPinary[i - 1+ arrPinary[i - 2];
            }
            
            System.out.println(arrPinary[iLength]);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Colored by Color Scripter

 

c++소스

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
#include <iostream>
 
using namespace std;
 
int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
 
    const int MAX = 90;
    long long S[MAX + 1= {01, };
 
    int n;
    cin >> n;
 
    /*
    D[N][i] : i로 끝나는 N자리의 이친수라 할때,
 
            S[N] = D[N][0] + D[N][1]
           D[N][0] = D[N - 1][0] + D[N - 1][1]                   = S[N - 1]
            D[N][1] = D[N - 1][0] = D[N - 2][0] + D[N - 2][1] = S[N - 2]
 
    --> 점화식 : S[N] = S[N - 1] + S[N - 2]
    */
    for (int i = 2; i <= n; i++)
    {
        S[i] = S[i - 1+ S[i - 2];
    }
 
    cout << S[n];
 
    return 0;
}
Colored by Color Scripter

 

바텀업이 더 효율적

 

 

TIP

1. 이친수는 0으로 시작하지 않는다.
2. 이친수에서는 1이 두 번 연속으로 나타나지 않는다. 즉, 11을 부분 문자열로 갖지 않는다.

 

이제 슬슬 패턴이 보이는 것 같다..?!

길이가 N인 이친수맨 끝자리가 0이 되려면, 앞에는 0, 1 모두 올 수 있다. 

길이가 N인 이친수맨 끝자리가 1이 되려면, 앞에는 0 만 올 수 있다.

 

길이가 N인 이친수끝자리가 k 인것을 D[N][k] 라 하자.

점화식으로 나타내면

 

D[N][0] = D[N - 1][0] + D[N - 1][1]

D[N][1] = D[N - 1][0]

 

그런데, 길이가 N -1 인 이친수끝자리가 0이려면 

그 앞자리에는 0 , 1 모두 와도 되므로

D[N][1] = D[N - 1][0] =D[N - 2][0] +D[N - 2][1

 

즉,

D[N][0] = D[N - 1][0] + D[N - 1][1]

D[N][1] = D[N - 2][0] +D[N - 2][1]

 

 

둘을 더하면

D[N][0] + D[N][1]

= D[N - 1][0] + D[N - 1][1] + D[N - 2][0] +D[N - 2][1]

 

 

이는 더 간단하게

D[N] = D[N - 1] + D[N - 2]   로 표현할 수 있다

댓글