[BOJ][Python3/PyPy3] 2248 - 이진수 찾기

2021. 1. 15. 17:56·알고리즘 (PS)/BOJ
반응형

동아리에서 DP를 배우면서 과제로 푼 '이진수 찾기'의 풀이 과정을 정리하고자한다.

처음에 문제를 딱 읽었을 때는 무슨 말인지 긴가민가 했다.

직접 써보면 간단하다.

 

만약 3자리 이진수 중, 2개 이하의 비트만 1인 것을 크기순으로 나열하면 다음과 같다.

000

001

010

011

100

101

110

 

이제 주어진 조건하에서 주어진 숫자 번째의 이진수를 찾아야한다.

처음에는 어떻게 풀어야할지 감이 안왔다.

그래서 예제 입력 1번 5 3 19 크기순으로 직접 나열해봤다.

 

00000

00001

00010

00011

00100

00101

00110

00111

01000

01001

01010

01011

01100

01101

01110

10000

.

.

.

근데 여기까지 쓰고보니 뭔가 규칙이 보인다.

 

위 사진처럼

00

01

10

11

이걸 반복해서 쓰고 있다.

이걸 자리수를 하나씩 늘려서 3자리 이진수로 묶어보고, 4자리 이진수로도 묶었을 때의 규칙을 보면

다음과 같은 규칙을 볼 수 있게 된다.

 

위의 예시의 경우

5자리 이진수 중 3개 이하의 비트를 1로 하는 모든 이진수의 개수는

첫번째 자리의 비트를 0으로 할 때 만들 수 있는 모든 숫자의 수

+

첫번째 자리의 비트를 1로 할 때 만들 수 있는 모든 숫자의 수

 

이를 규칙성을 보기 쉽게 바꿔쓰면 다음과 같이 쓸 수 있다.

 

4자리 이진수 중 3개 이하의 비트를 1로 하는 모든 이진수의 개수

+

4자리 이진수 중 2개 이하의 비트를 1로 하는 모든 이진수의 개수

 

첫번째 자리를 0으로 한다면 남은 4자리는 1을 최대 3개 쓸 수 있고,

첫번째 자리를 1로 한다면 남은 4자리는 1을 최대 2개 쓸 수 있다.

냅색 문제를 풀 때 떠올리는 아이디어와 비슷하다.

 

그리고 여기까지 나온 순간 이미 점화식이 세워져 버렸다ㅋㅋ

이제 N자리 이진수 중 M개 이하의 비트를 1로 하는 모든 이진수의 개수를

(N, M) 이라고 쓰도록 하자. (단, N >= M 이다.)

마치 조합을 보는 것 같은데, 파스칼 삼각형과 비슷한 느낌도 든다.

(이 문제 이항계수랑 관련있나?)

 

그러면

(N, M) = (N-1, M) + (N-1, M-1)

다음과 같은 식이 성립한다.

그리고 이 식으로부터 거꾸로 이진수를 찾아낼 수 있다.

 

그 이유는 (N-1, M) 이 유도된 과정이 맨 처음 자리수가 '0'일 때를 가정한 것이고,

(N-1, M-1)이 유도된 과정이 맨 처음 자리수가 '1'일 때를 가정한 것이기 때문이다.

그리고 우리는 이 이진수들을 크기순으로 정렬한 다음, 정렬된 이진수 중에서 특정 위치의 이진수를 찾는 것이 목적이다.

 

이해하기 쉽게 예제 입력 1을 기준으로 설명하면

(5, 3) = (4, 3) + (4, 2) 이다.

(4, 3) 이 의미하는게 무엇인가?

첫번째 자리는 0이라고 가정하고 나머지 4개의 자리만 볼 때,

4개중 최대 3개를 1로 할 수 있는 이진수들이다.

그럼 그 숫자는 무엇이 됐든 0 - - - - 의 형태이다.

 

같은 원리로 (4, 2)에 속하는 이진수들은

1 - - - -의 형태이다.

 

저 - - - -의 값에 상관없이

(4, 3) 에 속하는 이진수 < (4, 2)에 속하는 이진수 이다.

이분탐색을 떠올린다면 이제 풀이 법을 알 것이다.

만약 우리가 찾는 숫자가 (4, 3)에 속한다면

0 - - - - 의 형태이고

우리가 찾는 숫자가 (4, 2)에 속한다면

1 - - - - 의 형태이다.

 

따라서 (4, 3)의 값과 우리가 찾는 값을 비교하여

우리가 찾는 값이 더 크면 (4,2)에 속하는 수

우리가 찾는 값이 (4, 3)의 값과 같거나 작다면 (4, 3)에 속하는 수로 보고

첫번째 자리의 비트를 결정하면 된다.

 

이제 이 과정을 각 자리에 대해 반복하면 된다!

 

하지만 아직 처리하지 못한 부분이 있다.

첫번째로 N = M 일 때 어떻게 처리해야 할까?

간단하다.

2자리 이진수를 2개 이하의 1을 사용하여 모두 나타낸다면

00

01

10

11

사실상 모든 경우의 수를 적는 것과 같다.

그냥 2^N 개이다.

그리고 구조를 보면 첫번째 자리가 0인 이진수의 수와

첫번째 자리가 1인 이진수의 수가 같을 수 밖에 없다.

따라서 (N, N) = (N-1, N-1) + (N-1, N-1) 이다.

 

두번째로 M = 0 일 때 어떻게 처리하면 될까?

역시 간단하다.

2자리 이진수를 0개 이하의 1을 사용하여 모두 나타낸다면

00

하나 밖에 없다.

사실상 모든 자리수의 이진수에 대해서 똑같다. nCo 을 떠올려도 좋다.

따라서 (N, 0) = 0 이다.

 

따라서 이 2가지 특이 케이스와, 일반적인 케이스를 합쳐 점화식을 구성하면

다음과 같다.

 

마지막으로 이 알고리즘을 구현할 때는, DP테이블을 채우는 과정과 각 자리수를 결정하는 과정을 분리하여

따로 함수를 작성하였다.

 

# 2248 이진수 찾기
import sys
sys.setrecursionlimit(10**8)

def Fill_DP_Table(n_i, bit_i):
    if bit_i == 0:
        value = 1
    elif n_i == bit_i:
        if dp[n_i-1][bit_i-1] == -1:
            value = Fill_DP_Table(n_i-1, bit_i-1)
            value *= 2
        else:
            value = dp[n_i-1][bit_i-1]
    else:
        if dp[n_i-1][bit_i] == -1:
            v1 = Fill_DP_Table(n_i-1, bit_i)
        else:
            v1 = dp[n_i-1][bit_i]
        if dp[n_i-1][bit_i-1] == -1:
            v2 = Fill_DP_Table(n_i-1, bit_i-1)
        else:
            v2 = dp[n_i-1][bit_i-1]
        value = v1 + v2
    dp[n_i][bit_i] = value
    return value

def Print_Answer(n_i, bit_i, find, cnt):
    if bit_i == 0:
        if cnt < n:
            print(0, end='')
            Print_Answer(n_i, bit_i, find, cnt+1)

    elif n_i == bit_i:
        if dp[n_i-1][bit_i-1] < find:
            find -= dp[n_i-1][bit_i-1]
            print(1, end='')
        else:
            print(0, end='')
        Print_Answer(n_i - 1, bit_i - 1, find, cnt+1)
    else:
        if dp[n_i-1][bit_i] < find:
            find -= dp[n_i-1][bit_i]
            print(1, end='')
            Print_Answer(n_i-1, bit_i-1, find, cnt+1)
        else:
            print(0, end='')
            Print_Answer(n_i-1, bit_i, find, cnt+1)



n, bit, find = map(int, input().split())
dp = [[-1 for _ in range(bit+1)] for _ in range(n+1)]
Fill_DP_Table(n, bit)
Print_Answer(n, bit, find, 0)

 자리수를 결정하는 함수(Print_Answer)에서 bit_i = 0 일 때 바로 0을 출력하는 이유는

bit_i = 0 이라는 의미 자체가 1을 사용할 수 없다는 뜻이기 때문이다.

따라서 DP테이블의 값을 따질 필요없이 0을 출력하면 된다. 

반응형
저작자표시 비영리 변경금지 (새창열림)

'알고리즘 (PS) > BOJ' 카테고리의 다른 글

[BOJ][Python3] 5520 - The Clocks  (0) 2021.01.18
[BOJ][Python3/PyPy3] 7579 - 앱  (0) 2021.01.16
[BOJ][Python3/PyPy3] 13904 - 과제  (0) 2021.01.15
[BOJ][Python3/PyPy3] 15553 - 난로  (0) 2021.01.11
[BOJ][Python3/PyPy3] 5639 - 이진 검색 트리  (0) 2020.09.18
'알고리즘 (PS)/BOJ' 카테고리의 다른 글
  • [BOJ][Python3] 5520 - The Clocks
  • [BOJ][Python3/PyPy3] 7579 - 앱
  • [BOJ][Python3/PyPy3] 13904 - 과제
  • [BOJ][Python3/PyPy3] 15553 - 난로
에버듀
에버듀
개발은 좋은데 뭘로 개발할까
  • 에버듀
    Blog. 에버듀
    에버듀
  • 전체
    오늘
    어제
    • 분류 전체보기 (614)
      • 개인 프로젝트 (43)
        • 토이 프로젝트 (3)
        • [2020] 카카오톡 봇 (9)
        • [2021] 코드악보 공유APP (22)
        • [2022] 유튜브 뮤직 클론코딩 (9)
        • [2025] 한글 SQL 데이터베이스 (0)
      • 팀 프로젝트 (22)
        • [2020] 인공지능 숫자야구 (4)
        • [2022] OSAM 온라인 해커톤 (10)
        • [2024] GDSC 프로젝트 트랙 (6)
        • [2025] 큰소리 웹 페이지 (2)
      • CS (335)
        • 자료구조 (19)
        • 어셈블리 (41)
        • 멀티미디어응용수학 (7)
        • 컴퓨터 구조 (29)
        • 알고리즘 분석 (4)
        • 컴퓨터 네트워크 (38)
        • 프로그래밍언어론 (15)
        • HCI 윈도우즈프로그래밍 (26)
        • 기초데이터베이스 (29)
        • 운영체제 (23)
        • 오토마타 (24)
        • 문제해결기법 (11)
        • 블록체인 (22)
        • 소프트웨어공학 (21)
        • 기계학습심화 (12)
        • 컴퓨터그래픽스와 메타버스 (8)
        • 분산시스템특론 (6)
      • 자기계발 (44)
        • 생각 정리 (22)
        • 대외활동 (11)
        • 동아리 (7)
        • 자격증 (3)
        • 머니 스터디 (1)
      • 알고리즘 (PS) (107)
        • BOJ (101)
        • Programmers (5)
        • 알고리즘 이모저모 (1)
      • WEB(BE) (8)
        • express.js (1)
        • Spring & Spring Boot (7)
      • WEB(FE) (2)
        • html, css, js (1)
        • React.js (1)
      • Tool & Language (6)
        • Edit Plus (1)
        • Git (1)
        • Python3 (2)
        • Java (2)
      • Infra (12)
        • AWS (1)
        • Oracle Cloud (8)
        • Firebase (2)
        • Network (1)
      • Android (18)
        • Java (6)
        • Flutter (12)
      • Window (2)
        • Visual Studio 없이 WPF (1)
        • MFC (1)
      • 독서 (14)
        • Inside Javascript (7)
        • Database Internals (6)
        • 한 글 후기 (1)
  • 링크

    • github
    • website
  • 인기 글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
에버듀
[BOJ][Python3/PyPy3] 2248 - 이진수 찾기
상단으로

티스토리툴바