[백준] #1904번 01타일(Java)

Happy Jiwon·2024년 11월 23일
1

코테

목록 보기
2/8

백준 1904 - 01 타일 바로가기

📝 문제 설명

지원이에게 2진 수열을 가르쳐 주기 위해, 지원이 아버지는 그에게 타일들을 선물해주셨다.
그리고 이 각각의 타일들은 0 또는 1이 쓰여 있는 낱장의 타일들이다.

어느 날 짓궂은 동주가 지원이의 공부를 방해하기 위해
0이 쓰여진 낱장의 타일들을 붙여서 한 쌍으로 이루어진 00 타일들을 만들었다.
결국 현재 1 하나만으로 이루어진 타일 또는 한 쌍의 00타일들만이 남게 되었다.

그러므로 지원이는 타일로 더 이상 크기가 N인 모든 2진 수열을 만들 수 없게 되었다.
예를 들어, N=1일 때 1만 만들 수 있고, N=2일 때는 00, 11을 만들 수 있다.
(01, 10은 만들 수 없게 되었다.)
또한 N=4일 때는 0011, 0000, 1001, 1100, 1111 등 총 5개의 2진 수열을 만들 수 있다.

우리의 목표는 N이 주어졌을 때 지원이가 만들 수 있는 모든 가짓수를 세는 것이다.
단 타일들은 무한히 많은 것으로 가정하자.

  • 지원이가 갖고있는 타일의 종류는 1 타일과 0이 두개 붙여진 00 타일이다.

  • N=1일 때 1만 만들 수 있고, N=2일 때는 00, 11을 만들 수 있다.
    (01, 10은 만들 수 없게 되었다.)

  • N=4일 때는 0011, 0000, 1001, 1100, 1111 등 총 5개의 2진 수열을 만들 수 있다.

  • N이 주어졌을 때 지원이가 만들 수 있는 모든 가짓수를 세는 것이다. 단 타일들은 무한히 많은 것으로 가정한다.

입력
첫 번째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 1,000,000)

출력
첫 번째 줄에 지원이가 만들 수 있는 길이가 N인 모든 2진 수열의 개수를 15746으로 나눈 나머지를 출력한다.

입출력 예시


문제 들여다 보기..

나는 먼저 N이 6일때까지 만들 수 있는 2진수열의 가지 수를 표로 그려봤다.
(사실 더 많이 그려봄)

N 개수만들 수 있는 2진 수열가지 수
1 11
2 00, 112
3 001, 100, 1113
4 0000, 0011, 1001, 1100, 11115
5 00001, 00100, 00111, 10000, 10011, 11001, 11100, 111118
6 000000, 000011, 001100, 110000, 001001, 100001, 100100, 001111, 110011, 111100, 100111, 111100, 11111113

위 표에서 규칙성이 보이는데이렇게 쭉 그리다보면 가지수가 규칙성을 보이는 것을 알아챌 수 있다.

f(N) = f(N-1) + f(N-2)
ex
f(3) = f(2) + f(1) = 2 + 1 = 3
f(4) = f(3) + f(2) = 3 + 2 = 5
f(5) = f(4) + f(3) = 5 + 3 = 8
f(6) = f(5) + f(4) = 8 + 5 = 13

위 규칙은 피보나치 수인 것을 확인할 수 있다.

동적 프로그래밍 / 피보나치 수 간단 정의 보러가기


📌 풀이) DP 방식

public class Main {
    public static void main(String[] args) {
        int N = 4; // 2진 수열의 길이 N
        int[] tile = new int[num + 1]; // tile 배열 초기화
        System.out.print(dp(num, tile));
    }

    public static int dp(int i, int[] tile) {
        if (i <= 2) return i; // 기저 조건: F(1) = 1, F(2) = 2
        if (tile[i] == 0) tile[i] = (dp(i - 1, tile) + dp(i - 2, tile)) % 15746; // 모듈러 연산 유지
        return tile[i];
    }
}

📚 코드 설명

1️⃣ 입력 처리
사용자로부터 N 값을 입력받아 처리
N 은 1 ≤ N ≤ 1,000,000 로 제한
(입출력 예시로 4로 초기화 설정함)

2️⃣ 동적 계획법 배열 초기화
tile 배열은 이전에 계산한 값을 저장하기 위해 사용
tile[i]는 F(i) 값을 저장

3️⃣ 피보나치 계산 로직

  • 기저 조건
    F(1)=1, F(2)=2로 설정

  • 중복 계산 방지
    이미 계산된 값은 tile[i]에서 바로 반환

  • 점화식 적용
    계산되지 않은 경우(0인경우), F(n)=F(n−1)+F(n−2)로 값을 계산하고 tile[i]에 저장
    (15746을 나눈 나머지 값으로 저장)


🧠 시간 및 공간 복잡도 분석

시간 복잡도

  • 각 F(i)는 한 번만 계산되므로 시간 복잡도는 O(n) 이다.

공간 복잡도

  • 추가로 사용하는 dp 배열은 O(n) 의 공간을 차지한다.

전체코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int num = Integer.parseInt(br.readLine());
        int[] tile = new int[num + 1];
        System.out.print(dp(num, tile));
    }

    public static int dp(int i, int[] tile) {
        if (i <= 2) return i;
        if (tile[i] == 0) tile[i] = (dp(i - 1, tile) + dp(i - 2, tile)) % 15746;
        return tile[i];
    }
}

profile
공부가 조은 안드로이드 개발자

0개의 댓글