본문 바로가기
Problem Solving/Baekjoon Online Judge

[BOJ #1252] 이진수 덧셈

by DeveloperHan 2020. 7. 14.

BOJ #1252, 이진수 덧셈 문제입니다.

 

정답률은 28.3%로 상당히 낮습니다. 저 또한 문제의 세부 조건을 발견하지 못해 잠깐 헤맸습니다. 우선 이 문제는 크게 두 가지 방법이 있습니다. 첫 번째로 입력받은 이진수를 십진수로 변환하여 더하고, 다시 이진수로 변환하여 출력하는 방법이 있습니다. 두 번째로는 변환 없이 이진수 덧셈 자체를 구현하는 것이 되겠습니다.

 

첫 번째 방법은 어떻게 보면 더 효율적이고 더 빠른 방법일 수는 있겠으나, 문제의 의도는 아닐 것이라고 생각됩니다. 그리고 두 번째 방법으로 만들어보는 것이 실력적으로 더 큰 도움이 될 것입니다.

 

알고리즘은 동일하나, 이번 문제의 특성 상 C보단 Python으로 푸는 게 편리합니다. 저는 연습을 위해 일부러 C로 풀었지만 여기선 Python을 사용하도록 하겠습니다.

 

1. 이진수를 배열 형태로 만들기

이진수 덧셈을 구현하기 위해서는 두 이진수의 각 자릿수별 연산이 필수적이겠죠. 입력받은 이진수 문자열을 각각 a와 b라고 하면, int(a[index])로 다루면 됩니다. 그러나 매번 이 연산을 하는 것은 비효율적이기 때문에 이것을 반복 수행하여 a와 b를 a_list와 b_list로 만들겠습니다. 코드는 다음과 같습니다.

def bin_to_list(bin_str):
    res_list = []
    for i in range(len(bin_str)):
        res_list.append(int(bin_str[i]))

    return res_list


a, b = input('').split()
a_list = bin_to_list(a)
b_list = bin_to_list(b)

그러나 이 코드에는 문제가 있습니다. 바로 문제의 세부조건 때문입니다. 문제에 따르면, 각 이진수는 0으로 시작할 수도 있습니다. 즉, 0000001과 같은 입력이 가능하다는 것이죠. 위 코드를 사용해서 문제를 풀면, 실제 자릿수는 같으나 배열의 인덱스 상 자릿수는 달라지는 경우가 발생합니다. 앞부분의 0은 전혀 의미없는 숫자이므로, 그들을 버리고 배열화해야 합니다. bin_to_list 함수를 다음과 같이 개선하겠습니다.

def bin_to_list(bin_str):
    one_flag = False
    res_list = []
    for i in range(len(bin_str)):
        if bin_str[i] == '1':
            one_flag = True
        if one_flag:
            res_list.append(int(bin_str[i]))

    if not one_flag:
        return [0]

    res_list.reverse()
    return res_list

이렇게 하면 앞부분의 의미 없는 0을 쳐낼 수 있습니다. 1이 등장할 때까지 기다렸다가 1이 등장하면 flag를 True로 바꾸고 그때부터 append하기 시작하는 것이죠. 다만 0000000과 같이 입력된 경우는 별도로 처리를 해주어야 합니다. 저는 10번줄의 if문을 통해 처리를 했고 이 부분이 없으면 오류가 발생할 겁니다.

 

그리고 return 이전 .reverse() 메소드를 사용했는데, 크게 두 가지 이유가 있습니다. 첫 번째로는 자리올림을 편하게 하기 위해서입니다. 예를 들어 11 + 11 == 110인데, 마지막에 새로운 자리가 생긴 경우 .append()로 간단히 해결할 수 있게 됩니다. 물론 Python에서는 reverse하지 않고 사용해도 .insert()로 편하게 할 수 있겠지만 C로 풀 땐 이처럼 reverse해두고 푸는 것이 훨씬 편리합니다. 두 번째로 우리는 1의 자리부터 더해갈 것이기 때문입니다. 만약 두 이진수의 자릿수가 다르다면 index 처리를 따로따로 해주어야 하는데, reverse해두면 두 이진수에 대해 같은 index를 이용해 문제를 풀 수 있습니다.

 

2. 덧셈 구현

1의 자리부터 큰 자리를 차례로 더해 나갈 것이며, 올림을 고려해야 합니다. 우선 한 자리 이진수끼리 더하는 경우는 다음의 3가지 경우가 있겠습니다.

  • 0 + 0 == 0
  • 0 + 1 == 1
  • 1 + 1 == 10 == 1(올림)

여기서 올림을 고려하면, 다음 세 가지의 경우가 추가됩니다.

  • 0 + 0 + 1(올려진 값) == 1
  • 0 + 1 + 1(올려진 값) == 10 == 1(올림)
  • 1 + 1 + 1(올려진 값) == 11 == 1(올림) + 1

그런데 올림의 여부와는 상관없이 덧셈의 결과값은 피연산자들의 총합과만 관계됩니다. 따라서 up이 올려진 값이 저장된 변수라고 하면 a_list[index] + b_list[index] + up에 따라 분기하면 되겠습니다. 물론 상세 case별로 올림 처리를 해 주어야 합니다. 이 부분이야말로 이번 문제의 핵심이므로, 직접 구현해보시기 바랍니다.

 

저는 더 짧은 이진수 배열까지만 덧셈 처리를 했는데, 만약 마지막에 올림된 1이 남은 경우에 대해서도 처리해주어야 했습니다. 이러한 점과 덧셈을 한 이후엔 결과를 그대로 출력하되, 거꾸로 출력해야 한다는 점에 유의하여 직접 코딩해보시면 얻어가는 것이 아주 많을 문제라고 생각됩니다.

 

3. 전체 코드

더보기
def bin_to_list(bin_str):
    one_flag = False
    res_list = []
    for i in range(len(bin_str)):
        if bin_str[i] == '1':
            one_flag = True
        if one_flag:
            res_list.append(int(bin_str[i]))

    if not one_flag:
        return [0]

    res_list.reverse()
    return res_list


def print_binary(bin_str):
    for i in range(len(bin_str)):
        print(bin_str[len(bin_str) - 1 - i], end='')
    print('')


a, b = input('').split()
a_list = bin_to_list(a)
b_list = bin_to_list(b)

if len(a_list) < len(b_list):
    tmp_list = a_list[:]
    a_list = b_list[:]
    b_list = tmp_list[:]

up = 0
for i in range(len(b_list)):
    part_sum = up + a_list[i] + b_list[i]
    if part_sum == 0:
        up = 0
        a_list[i] = 0
    elif part_sum == 1:
        up = 0
        a_list[i] = 1
    elif part_sum == 2:
        up = 1
        a_list[i] = 0
    elif part_sum == 3:
        up = 1
        a_list[i] = 1

if up == 1:
    if len(a_list) == len(b_list):
        a_list.append(1)
    else:
        for i in range(len(b_list), len(a_list)):
            if a_list[i] == 0:
                a_list[i] = 1
                break
            elif a_list[i] == 1:
                a_list[i] = 0
                if i == len(a_list) - 1:
                    a_list.append(1)
                    break

print_binary(a_list)

32번줄부터가 덧셈을 처리하는 과정이고, 48번줄부터가 덧셈 이후 올림된 1이 남은 상황을 처리하는 과정입니다. .append()를 사용해서 깔끔하게 처리가 가능하기에 배열을 reverse해서 저장한 것도 있습니다.

 

'Problem Solving > Baekjoon Online Judge' 카테고리의 다른 글

[BOJ #11728] 배열 합치기  (0) 2020.07.18
[BOJ #2231] 분해합  (0) 2020.07.15
[BOJ #2447] 별 찍기 - 10  (0) 2020.07.14
[BOJ #1543] 문서 검색  (0) 2020.07.14
[BOJ #15965] K번째 소수  (0) 2020.07.13

댓글