Skip to content

Conversation

@Mingguriguri
Copy link
Collaborator

@Mingguriguri Mingguriguri commented Apr 12, 2025

🌱WIL

이번 한 주의 소감을 작성해주세요!

  • 정말 오랜만에 코테 문제를 풀이했다. 지난 주 스킬체크도 그렇고 스터디할 때도 그렇고 너무 오랫동안 안 푸니까 뇌가 굳는 느낌이었다. 앞으로 다시 심기일전해서 꾸준히 풀어야겠다.
  • 이번 주는 DP 문제를 풀이했다. 그 중에서도 가장 기억에 남는 건 계단수 문제와 극장좌석 문제이다.
    • 계단수 문제의 경우 비트마스킹을 사용한다는 것이 새로웠다. 비트마스킹은 이론적으로는 아는 개념인데 이를 DP에 어떻게 적용하는지가 관건이었고 어려운 부분이었다. 이 문제를 통해서 << 연산자가 언제, 왜 쓰이는지를 이번 기회에 정확히 알 수 있었다.
    • 극장좌석 문제의 경우, 문제의 겉모습에서는 전혀 피보나치 수열의 규칙성이 보이지 않지만 조금 더 들여다보면 피보나치 수열이 사용되는 것이 놀라웠다. 피보나치 수열의 가능성을 다른 문제를 풀 때도 열어둬야겠다. 또한 VIP 좌석을 기준으로 구간을 나누고, 각 구간의 경우의 수를 따로 구해 곱하는 방식은 다른 문제에도 응용할 수 있을 것 같다.
  • 다음 주에는 DP 문제도 풀고, 그래프 문제도 풀어야겠다. DP만 풀다가 다시 그래프 봤을 때 하나도 못 풀까봐 조금 걱정된다

🚀주간 목표 문제 수: 3개

푼 문제


백준 #10844. 쉬운 계단 수: DP / 실버1

정리한 링크: (바로가기)

🚩제출한 코드

import sys
input = sys.stdin.readline

'''
DP에는 길이가 i고 j가 마지막 수의 개수가 저장되어야 한다.
'''

N = int(input())
dp = [[0 for _ in range(10)] for _ in range(N+1)]
for i in range(1, 10):
    dp[1][i] = 1

for i in range(2, N+1):
    for j in range(10):
        if j == 0:
            dp[i][j] = dp[i-1][1]
        elif j == 9:
            dp[i][j] = dp[i-1][8]
        else:
            dp[i][j] = dp[i-1][j-1] + dp[i-1][j+1]

print(sum(dp[N]) % 1000000000)

💡TIL

배운 점이 있다면 입력해주세요

  • 분기를 나눠서 처리할 것!

백준 #2193. 이친수: DP / 실버3

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. N을 입력받는다.
  2. dp 배열을 초기화한다. (N+1 길이로 생성)
  3. dp[1] = 1로 초기값을 설정한다.
  4. i가 2부터 N까지 반복하면서 점화식에 따라 값을 채워나간다.
  5. 마지막 결과값인 dp[N]을 출력한다.

🚩제출한 코드

import sys
input = sys.stdin.readline

N = int(input())
dp = [0] * (N + 1)
dp[1] = 1

for i in range(2, N + 1):
    dp[i] = dp[i - 1] + dp[i - 2]

print(dp[N])

💡TIL

배운 점이 있다면 입력해주세요

  • 오랜만에 간단한 DP 문제를 푸니까 좋다..ㅎ
  • 역시나 규칙성을 파악하는 게 DP 문제의 핵심이라는 걸 다시 느꼈다!

백준 #1562. 계단수: DP / 골드1

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 입력 받기

    • 정수 N을 입력 받는다. (계단 수의 길이)
    • 모듈러 연산을 위한 MOD = 10^9 설정
  2. DP 배열 정의

    • dp[n][last][mask]

      길이가 n, 끝자리 숫자가 last, 지금까지 등장한 숫자의 비트마스크가 mask인 경우의 수

  3. 초기화

    • 길이 1인 수는 1~9로 시작할 수 있으므로, 각 숫자에 대해 비트마스크 초기화
  4. 점화식 적용

    • 길이 2부터 N까지 반복하며 계단 수 규칙(±1)에 따라 이전 상태로부터 값을 누적
    • 등장한 숫자를 비트마스크로 갱신하면서 저장
  5. 정답 계산

    • 비트마스크가 0b1111111111(=1023)인 경우만 누적해서 출력

🚩제출한 코드

import sys
input = sys.stdin.readline

# 1. 입력
N = int(input())
MOD = 10**9


# 2. DP 정의
# dp[n][last_digit][bitmask]
# n: 숫자 길이, last_digit: 마지막 자리 숫자, bitmask: 지금까지 어떤 숫자들이 나왔는지 (비트마스크)
# 범위 - n: 입력값, last_digit: 0~9, bitmask: 0~1023
dp = [[[0 for _ in range(1024)] for _ in range(10)] for _ in range(N+1)]

# 3. 초기상태 설정
# 길이가 1일 때, 0을 제외하고 1~9로 시작할 수 있음
for i in range(1, 10):
    dp[1][i][1 << i] = 1

# 4. 점화식대로 DP 채우기
# n: N번째 수
for n in range(2, N+1):
		# last_digit: 마지막 자리 숫자  
    for last_digit in range(10):
        # 0~9까지 모든 수를 방문해야 한다는 조건이 있으므로 방문여부를 비트마스킹을 통해 저장
        for mask in range(1024):
            if last_digit == 0:
                dp[n][last_digit][mask | (1 << last_digit)] += dp[n - 1][last_digit + 1][mask]
            elif last_digit == 9:
                dp[n][last_digit][mask | (1 << last_digit)] += dp[n - 1][last_digit - 1][mask]
            else:
                dp[n][last_digit][mask | (1 << last_digit)] += (
                        dp[n - 1][last_digit - 1][mask] + dp[n - 1][last_digit + 1][mask]
                )
            dp[n][last_digit][mask | (1 << last_digit)] %= MOD

# 5. 정답 계산 및 출력
answer = 0
for i in range(10):
    # N자리 수 중에서 i로 끝나는 수 중 0부터 9까지 다 있는 수를 누적해서 더하기
    answer += dp[N][i][1023]

print(answer % MOD)

💡TIL

배운 점이 있다면 입력해주세요

    • 처음에 짠 내 코드는 "모든 자리 수가 0~9를 다 포함해야 한다"는 조건을 놓쳐서 오답이었다.
  • 비트마스킹에 대해서 개념적으로만 알고 있었는데,

    실제로 문제 풀이에 활용하려 하니까 헷갈리는 부분이 많았다.

  • 특히 << 연산자가 언제, 왜 쓰이는지를 이번 기회에 정확히 알 수 있었다.

  • 전체적으로 비트마스크를 활용한 DP 문제의 구조와 패턴을 체득할 수 있었던 좋은 경험이었다.


백준 #2302. 극장 좌석: DP / 실버1

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 입력 처리

    • 좌석 개수 N, VIP 좌석 개수 M, VIP 좌석 번호를 입력받는다.
  2. DP 배열 초기화

    • dp[i]: VIP가 없을 때, 연속된 i개의 좌석에서 가능한 배치의 수
    • 점화식은 dp[i] = dp[i-1] + dp[i-2]
    • 초기값은 dp[0] = 1, dp[1] = 1
  3. VIP 좌석 기준으로 구간 나누기

    • VIP 전까지의 자유 좌석 구간 길이를 계산하고,

      그 구간에서 가능한 배치 수 dp[구간 길이]를 누적해서 곱한다.

  4. 마지막 구간 처리

    • 마지막 VIP 이후 남은 좌석 구간에 대해서도 동일하게 처리
  5. 결과 출력

🚩제출한 코드

import sys
input = sys.stdin.readline

# 1. 입력
N = int(input())  # 좌석의 개수
M = int(input())  # 고정석의 개수
vip_list = [int(input()) for _ in range(M)]  # VIP 고정석 번호 리스트

# 2. DP 초기화
dp = [0] * (N + 1)
dp[0], dp[1] = 1, 1

# 3. 피보나치 수열 기반 DP 채우기
for i in range(2, N+1):
    dp[i] = dp[i-1] + dp[i-2]

# 4. 좌석 구간별 계산
answer = 1
prev = 0  # 이전 VIP 좌석 번호

for vip in vip_list:
    section = vip - prev - 1  # VIP 좌석 전까지 자유 좌석 구간 길이
    answer *= dp[section]     # 그 구간에서 가능한 배치 수 곱하기
    prev = vip                # 현재 VIP를 기준으로 다음 구간 나눌 준비

# 5. 마지막 구간 처리 (VIP 이후 남은 좌석이 있는 경우)
section = N - prev
answer *= dp[section]

print(answer)

💡TIL

배운 점이 있다면 입력해주세요

  • 피보나치 수열은 정말 다양한 곳에 쓰인다. 이 문제도 그렇게 생긴 문제라는 걸 처음엔 눈치채지 못했다.
  • VIP 좌석을 기준으로 구간을 나누고, 각 구간의 경우의 수를 따로 구해 곱하는 방식은 다른 문제에도 응용할 수 있을 것 같다.
  • 생각보다 구현은 간단한데, 접근법을 떠올리는 게 어려웠던 문제였다. 비슷한 문제를 더 연습해봐야겠다고 느꼈다.

Copy link
Member

@YoonYn9915 YoonYn9915 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

계단수 문제 잘 푸셨나요? 저는 아직 이해가 잘 안됩니다..

한주 수고하셨습니다

@Mingguriguri Mingguriguri merged commit ceca9a5 into main Apr 14, 2025
@github-actions
Copy link

🔥2025-04 챌린지 진행 상황

👉 그래프

  • YoonYn9915: 0개 ❌
  • Mingguriguri: 0개 ❌

👉 DP

  • YoonYn9915: 2개 ❌
  • Mingguriguri: 4개 ❌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants