완전탐색(유형정리) - 백준 2503
2503번: 숫자 야구
첫째 줄에는 민혁이가 영수에게 몇 번이나 질문을 했는지를 나타내는 1 이상 100 이하의 자연수 N이 주어진다. 이어지는 N개의 줄에는 각 줄마다 민혁이가 질문한 세 자리 수와 영수가 답한 스트
www.acmicpc.net
문제
정보문화진흥원 정보 영재 동아리에서 동아리 활동을 하던 영수와 민혁이는 쉬는 시간을 틈타 숫자야구 게임을 하기로 했다.
- 영수는 1에서 9까지의 서로 다른 숫자 세 개로 구성된 세 자리 수를 마음속으로 생각한다. (예: 324)
- 민혁이는 1에서 9까지의 서로 다른 숫자 세 개로 구성된 세 자리 수를 영수에게 묻는다. (예: 123)
- 민혁이가 말한 세 자리 수에 있는 숫자들 중 하나가 영수의 세 자리 수의 동일한 자리에 위치하면 스트라이크 한 번으로 센다. 숫자가 영수의 세 자리 수에 있긴 하나 다른 자리에 위치하면 볼 한 번으로 센다.
예) 영수가 324를 갖고 있으면
- 429는 1 스트라이크 1 볼이다.
- 241은 0 스트라이크 2 볼이다.
- 924는 2 스트라이크 0 볼이다.
- 영수는 민혁이가 말한 수가 몇 스트라이크 몇 볼인지를 답해준다.
- 민혁이가 영수의 세 자리 수를 정확하게 맞추어 3 스트라이크가 되면 게임이 끝난다. 아니라면 민혁이는 새로운 수를 생각해 다시 영수에게 묻는다.
현재 민혁이와 영수는 게임을 하고 있는 도중에 있다. 민혁이가 영수에게 어떤 수들을 물어보았는지, 그리고 각각의 물음에 영수가 어떤 대답을 했는지가 입력으로 주어진다. 이 입력을 바탕으로 여러분은 영수가 생각하고 있을 가능성이 있는 수가 총 몇 개인지를 알아맞혀야 한다.
아래와 같은 경우를 생각해보자.
- 민혁: 123
- 영수: 1 스트라이크 1 볼.
- 민혁: 356
- 영수: 1 스트라이크 0 볼.
- 민혁: 327
- 영수: 2 스트라이크 0 볼.
- 민혁: 489
- 영수: 0 스트라이크 1 볼.
이때 가능한 답은 324와 328, 이렇게 두 가지이다.
영수는 동아리의 규율을 잘 따르는 착한 아이라 민혁이의 물음에 곧이곧대로 정직하게 답한다. 그러므로 영수의 답들에는 모순이 없다.
민혁이의 물음들과 각각의 물음에 대한 영수의 답이 입력으로 주어질 때 영수가 생각하고 있을 가능성이 있는 답의 총 개수를 출력하는 프로그램을 작성하시오.
입력
첫째 줄에는 민혁이가 영수에게 몇 번이나 질문을 했는지를 나타내는 1 이상 100 이하의 자연수 N이 주어진다. 이어지는 N개의 줄에는 각 줄마다 민혁이가 질문한 세 자리 수와 영수가 답한 스트라이크 개수를 나타내는 정수와 볼의 개수를 나타내는 정수, 이렇게 총 세 개의 정수가 빈칸을 사이에 두고 주어진다.
출력
첫 줄에 영수가 생각하고 있을 가능성이 있는 답의 총 개수를 출력한다.
예제 입력 1 복사
4
123 1 1
356 1 0
327 2 0
489 0 1
예제 출력 1 복사
2
위 문제에서는 기본적으로 1~9의 숫자를 가지고 3개로 만들어진 순열을 리스트로 만들어 놓는 것이 핵심이다.
이 리스트를 먼저 형성시켜둔 후에 아래의 알고리즘을 따라 가면 된다.
※ 알고리즘
1. num, strike, ball 변수를 통해서 입력을 시켜준다.
2. list를 num변수의 문자열로 담아서 만들어준다.
3. 항상 0 index 부터 시작해야하므로 count를 계속해서 빼준다.
4. answer sheet와 입력 숫자를 index 비교하고 같으면 strike의 count를 +1
5. answer sheet와 입력 숫자의 index 비교 시 같지는 않은데 안에 있으면 ball의 count를 +1
6. strike와 ball이 수에 맞지 않으면 해당 index를 answer 배열에서 삭제 시켜 버리고 그 길이 만큼을 출력시킨다.
from itertools import permutations
N = int(input())
number = ['1','2','3','4','5','6','7','8','9']
answer = list(permutations(number, 3))
for i in range(N):
num, strike, ball = map(int, input().split())
lists = list(str(num))
count = 0
for j in range(len(answer)):
j = j - count #항상 0 index부터 비교시작
strike_count = 0
ball_count = 0
for k in range(3):
if answer[j][k] == lists[k]: #answer sheet와 입력 숫자를 index 비교해서 같으면 strike
strike_count += 1
elif lists[k] in answer[j]: #입력숫자가 answer sheet와 같지는 않은데 안에 있으면 ball
ball_count += 1
if strike_count != strike or ball_count != ball:
answer.remove(answer[j])
count += 1 #strike와 ball이 수에 맞지 않으면 해당 index를 answer 배열에서 제거
print(len(answer))
항상 0 index 부터 비교한다는 것을 놓치면 하루종일 알고리즘에 맞는 순서대로 비교하여 구현하더라도 제대로 된 값이 나타나지 않는다. 0 index 부터 비교를 한다는 것과 처음에 기본 순열을 만들어 주는 것이 핵심이다.
역시 코테는 숨어 있는 함정을 찾는 싸움인 것 같다...