Original Source: https://www.acmicpc.net/problem/6603
6603번: 로또
입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있다. 첫 번째 수는 k (6 < k < 13)이고, 다음 k개 수는 집합 S에 포함되는 수이다. S의 원소는 오름차순으로
www.acmicpc.net
문제
독일 로또는 {1, 2, ..., 49}에서 수 6개를 고른다.
로또 번호를 선택하는데 사용되는 가장 유명한 전략은 49가지 수 중 k(k>6)개의 수를 골라 집합 S를 만든 다음 그 수만 가지고 번호를 선택하는 것이다.
예를 들어, k=8, S={1,2,3,5,8,13,21,34}인 경우 이 집합 S에서 수를 고를 수 있는 경우의 수는 총 28가지이다. ([1,2,3,5,8,13], [1,2,3,5,8,21], [1,2,3,5,8,34], [1,2,3,5,13,21], ..., [3,5,8,13,21,34])
집합 S와 k가 주어졌을 때, 수를 고르는 모든 방법을 구하는 프로그램을 작성하시오.
입력
입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있다. 첫 번째 수는 k (6 < k < 13)이고, 다음 k개 수는 집합 S에 포함되는 수이다. S의 원소는 오름차순으로 주어진다.
입력의 마지막 줄에는 0이 하나 주어진다.
출력
각 테스트 케이스마다 수를 고르는 모든 방법을 출력한다. 이때, 사전 순으로 출력한다.
각 테스트 케이스 사이에는 빈 줄을 하나 출력한다.
사고의 흐름
- 우선 내장 함수를 쓰지 않고 코드를 작성해보자.
- 6개의 수를 선택하는 경우를 처음부터 생각하기는 까다로우니 2개의 수를 선택하는 경우를 먼저 생각해보자.
- 2개의 변수 i, j를 사용해서 i에 List의 첫 번째 원소, j에 두 번째 원소를 할당한다. 이후 j를 끝까지 증가시키면서 숫자들을 출력하고, j가 끝까지 가면 i의 Index를 하나 증가시켜 두 번째 원소를 할당하고 j에 i 다음의 세 번째 원소를 할당한다. 즉 이중 반복문이다.
- 그럼 6개의 수를 선택하면 6중 반복문인가?
- k의 범위가 6 < k < 13 밖에 안 되니 가능할 것 같다.
- 반복문으로 구현해서 맞긴 했는데, 재귀로 구현하는 편이 확실히 편해 보인다. 재귀로도 구현해보자.
- 재귀 구현은 포기해야겠다. 그래도 어찌어찌 따라서 하긴 했긴 하지만, 다른 사람이 짠 코드를 봐도 잘 이해가 안 된다.
- 마지막으로 itertools의 combinations를 쓰면 어떨까?
- combinations를 쓰니까 코드가 말도 안 되게 간결해졌다. 정말 Python은 사기다.
내가 작성한 소스코드
# 반복문
import sys
for line in sys.stdin:
numbers = list(map(int, line.split()))
if numbers[0] == 0:
sys.exit(0)
else:
del numbers[0]
indices = [0, 1, 2, 3, 4, 5]
for indices[0] in range(indices[0], len(numbers)):
for indices[1] in range(indices[0]+1, len(numbers)):
for indices[2] in range(indices[1]+1, len(numbers)):
for indices[3] in range(indices[2]+1, len(numbers)):
for indices[4] in range(indices[3]+1, len(numbers)):
for indices[5] in range(indices[4]+1, len(numbers)):
for idx in indices:
print(numbers[idx], end=" ")
print()
print()
# 재귀
import sys
def select_num(lotto, i):
if len(lotto) == 6:
for v in lotto:
print(v, end=" ")
print()
return
if i == len(numbers): return
lotto.append(numbers[i])
select_num(lotto, i+1)
del lotto[-1]
select_num(lotto, i+1)
numbers = []
for line in sys.stdin:
numbers = list(map(int, line.split()))
if numbers[0] == 0:
sys.exit(0)
else:
del numbers[0]
select_num([], 0)
print()
# 내장 함수
import sys
from itertools import combinations
numbers = []
for line in sys.stdin:
numbers = list(map(int, line.split()))
if numbers[0] == 0:
sys.exit(0)
else:
del numbers[0]
for v in combinations(numbers, r=6):
for w in v:
print(w, end=" ")
print()
print()
남이 작성한 소스코드
chapp 님:
https://www.acmicpc.net/source/18091717 (재귀)
피드백
- 재귀 함수 더 공부하자. DPS 문제들을 풀면 감이 잡히겠다.
'BOJ' 카테고리의 다른 글
[실버 1] 1697번: 숨바꼭질 (0) | 2022.09.12 |
---|---|
[실버 4] 2407번: 조합 (0) | 2022.09.11 |
[골드 4] 9019번: DSLR (0) | 2022.09.09 |
[실버 3] 11726번: 2×n 타일링 (0) | 2022.09.07 |
[실버 3] 1966번: 프린터 큐 (0) | 2022.08.27 |