문제풀이/백트래킹

[Python/파이썬] 백준 6603번 로또

딜레이레이 2023. 12. 24. 13:00
 

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이 하나 주어진다. 



출력

각 테스트 케이스마다 수를 고르는 모든 방법을 출력한다. 이때, 사전 순으로 출력한다.

각 테스트 케이스 사이에는 빈 줄을 하나 출력한다.



코드

백트래킹을 이용한 풀이

def bt(candidate, idx, selected):
    if len(selected) == 6:  # 6개 다 뽑음
        print(*selected)
        return
    if idx >= len(candidate):
        return
    bt(candidate, idx+1, selected+[candidate[idx]])   # idx 포함
    bt(candidate, idx+1, selected)                  # idx 포함 X


while True:
    input_data = list(map(int, input().split()))
    if input_data[0] == 0:
        break
    bt(input_data[1:], 0, [])
    print()

bt()

  • 숫자를 6개 다 뽑거나 고를 수 있는 후보들의 집합인 candidate의 길이보다 인덱스의 수가 커지게 되면 더이상 탐색할 필요가 없기 때문에 리턴한다. 이때 숫자를 6개 다 뽑은 경우에는 그 숫자들을 한 줄로 출력해준다.
  • 그렇지 않다면 cadidate의 idx번째 원소를 포함하는 경우와 포함하지 않는 경우 두 가지로 나누어 재귀적으로 계속 탐색을 진행한다.

 

 

조합(combinations)을 이용한 풀이

from itertools import combinations

while True:
    input_data = list(map(int, input().split()))
    if input_data[0] == 0:
        break
    k = input_data[0]
    s = input_data[1:]
    for comb in combinations(s, 6):
        print(*comb)
    print()

입력으로 주어진 집합 s에서 6개를 뽑을 수 있도록 itertools 라이브러리의 combinations를 이용했다.