즐거운 PS 👩‍💻🥰

[백준-파이썬] 17349: 1루수가 누구야

dalin❤️ 2022. 1. 19. 22:12

문제 보러 가기!

구현 문제!
처음에는 엄청 간단하게만 생각했는데, 아니었다. 생각해야 할 게 많았다..

나는 한 명씩 거짓말쟁이로 가정하고, 정답이 될 수 있는 것들을 다 모았다.
정답이 될 수 있는 게 하나라면, 정답으로 출력하면 된다.
정답이 될 수 있는 게 없거나, 여러 개라면 정답이 확정이 안되는 것이니까 -1를 출력하면 된다.

한 명을 거짓말쟁이로 가정한 상태에서 정답이 뭐가 될 수 있는지 봐주기 위해서, 매번 baseman_arr 리스트를 만들었다. 1번~ 9번에 대해서, 1루수라고 하는지 아니라고 하는지를 저장했따. 초기값은 -1로 해둔 후에, 해당 번호의 사람이 1루수라고 하면 1을, 아니라고 하면 0을 저장했다.

모순이 생긴다면 바로 break를 했고, 그렇지 않다면 모든 사람의 말을 들어본 후에 baseman_arr를 봐주었다. baseman_arr에서 1루수라는 표시가 1개라면, 그 번호가 정답이 될 수 있다고 모았다. baseman_arr에서 1루수라는 표시가 없으면, 아무 표시가 없는 아이들(-1)도 1루수가 될 가능성이 있으므로 정답이 될 수 있다고 모았다.

고려해야 할 것들...

  • 거짓말쟁이로 가정한 사람의 이야기는 반대로 baseman_arr에 저장해야 한다.
  • 거짓말쟁이의 말과 똑같이 말하는 사람이 있으면, 모순이 된다.
  • 거짓말쟁이가 아닌 경우.
    • 맞다고 증언한 사람이 있는데(baseman_arr가 1), 아니라는 사람이 있으면 모순
    • 아니라고 증언한 사람이 있는데(baseman_arr가 0), 맞다는 사람이 있으면 모순
  • 게시판의 반례와 설명이 문제를 이해하는 데 큰 도움이 되었다.

코드 

import sys

input = sys.stdin.readline
MIIS = lambda: map(int, input().split())

testimonies = []

for _ in range(9):
    a, b = MIIS()
    testimonies.append((a, b))

candidates = []
for liar in range(9):  # 그 사람이 거짓말한다고 가정하고 볼 것
    baseman_arr = [100] + [-1] * 9  # 각 사람들이 1루수인지?
    liar_speak = [-1, -1]

    for i in range(9):

        is_baseman, baseman_num = testimonies[i]
        if i == liar:  # 거짓말 쟁이로 가정한 사람 이야기대로 말한 사람이 있으면 모순
            if baseman_arr[baseman_num] == is_baseman:
                break
            baseman_arr[baseman_num] = (1 + is_baseman) % 2  # 거짓말의 반대

            liar_speak = [is_baseman, baseman_num]
            continue

        # 만약 거짓말쟁이의 이야기와 똑같이 이야기하는 사람 있으면 모순
        if liar_speak != -1 and liar_speak[0] == is_baseman and liar_speak[1] == baseman_num:
            break

        if is_baseman == 0 and baseman_arr[baseman_num] != 1:  # 아니라고 증언했고, 맞다는 증언이 없으면
            baseman_arr[baseman_num] = 0  # 아니라고 표시

        elif is_baseman == 0 and baseman_arr[baseman_num] == 1:  # 아니라고 증언했는데, 맞다는 증언이 있으면
            break  # 모순!

        elif is_baseman == 1 and baseman_arr[baseman_num] == 0:  # 맞다고 증언했는데, 아니라는 증언이 있으면
            break  # 모순!

        elif is_baseman == 1 and baseman_arr[baseman_num] != 0:  # 맞다고 증언했는데, 아니라는 증언이 없으면
            baseman_arr[baseman_num] = 1  # 맞다고 표시

    else:  # break 안 나왔으면 baseman_arr를 쭉 보기!
        if baseman_arr.count(1) == 0:  # 모순이 없고, 아니라는 표시가 없으면 그 아이들 다 될 수 있음.
            for j in range(1, 10):
                # 그런데 거짓말쟁이 말대로는 안됨.
                if j == liar_speak[1] and liar_speak[0] == 1:
                    continue
                if baseman_arr[j] == -1:
                    candidates.append(j)

        elif baseman_arr.count(1) == 1:  # 1루수라는 표시가 1개이면
            candidates.append(baseman_arr.index(1))

if len(set(candidates)) == 1:
    print(candidates[0])
else:  # 답 구할 수 없는 경우
    print(-1)
728x90