BOJ 6603 - 로또 문제풀이
문제를 읽고 이해하기
독일 로또는 {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이 하나 주어진다.
출력
각 테스트 케이스마다 수를 고르는 모든 방법을 출력한다. 이때, 사전 순으로 출력한다.
각 테스트 케이스 사이에는 빈 줄을 하나 출력한다.
재정의와 추상화
이 문제를 처음 보자마자 C++ STL의 Permutation 관련 함수들이 떠올랐다. 입력받은 k개의 수 중에서 6개를 뽑는 조합의 수를 만드는 것이니, k개의 원소가 오름차순으로 정렬된 vector와, 1이 6개 0이 k - 6개가 순차적으로 들어가있는 vector를 통해 구현할 수 있다.
아래 예시를 보면 이해가 될 것이다!
테스트 케이스에서 주어진 k = 7, v = [ 1, 2, 3, 4, 5, 6, 7 ]을 이용할 때, 우리는 6개를 뽑는 것이기 때문에 1이 6개, 0이 1개(k - 6)가 포함된 벡터 ind = [ 1, 1, 1, 1, 1, 1, 0 ]을 이용한다.
1과 0으로 이루어진 벡터를 next_permutation() 함수를 이용한다.
[ 1, 1, 1, 1, 1, 1, 0 ] -> [ 1, 1, 1, 1, 1, 0, 1 ] -> [ 1, 1, 1, 1, 0, 1, 1 ] -> [ 1, 1, 1, 0, 1, 1, 1 ] -> [ 1, 1, 0, 1, 1, 1, 1 ] ...
v[ind에서 1에 해당하는 곳의 인덱스]만 출력하고, v[ind에서 0에 해당하는 곳의 인덱스]는 출력하지 않으면 된다.
따라서, 8개의 원소를 가지는 집합에서 6개를 고르는 방법은 아래와 같이 표현 가능하다.
ind = [ 1, 1, 1, 1, 1, 1, 0 ] -> [ 1, 1, 1, 1, 1, 0, 1 ] -> [ 1, 1, 1, 1, 0, 1, 1 ] -> [ 1, 1, 1, 0, 1, 1, 1 ] -> [ 1, 1, 0, 1, 1, 1, 1 ] ...
v = [ 1, 2, 3, 4, 5, 6, 7 ] -> [ 1, 2, 3, 4, 5, 6, 7 ] -> [ 1, 2, 3, 4, 5, 6, 7 ] -> [ 1, 2, 3, 4, 5, 6, 7 ] -> [ 1, 2, 3, 4, 5, 6, 7 ]
C++ STL의 next_permutation()을 이용한 방법 외에도 DFS와 백트래킹을 이용한 방법도 있다.
코드 작성
// C++ STL Permutation 관련 함수를 이용한 방법
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
cin.sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int k;
while (cin >> k && k) {
vector<int> v;
vector<int> ind;
if (k == 0)
break;
for (int i = 0; i < k; i++) {
int temp;
cin >> temp;
v.push_back(temp);
}
for (int i = 0; i < 6; i++)
ind.push_back(1);
for (int i = 0; i < k - 6; i++)
ind.push_back(0);
do {
for (int i = 0; i < ind.size(); i++) {
if (ind[i])
cout << v[i] << ' ';
}
cout << '\n';
} while (prev_permutation(ind.begin(), ind.end()));
v.clear();
ind.clear();
cout << '\n';
}
return 0;
}
// DFS와 백트래킹을 이용한 방법
#include <iostream>
#include <vector>
using namespace std;
vector<int> numbers;
vector<int> lottos;
int n;
void dfs(int start, int count) {
if (count == 6) {
for (int i = 0; i < 6; i++)
cout << lottos[i] << ' ';
cout << '\n';
return;
}
for (int i = start; i < n; i++) {
lottos.push_back(numbers[i]);
dfs(i + 1, count + 1);
lottos.pop_back();
}
}
int main() {
cin.sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
while (cin >> n && n) {
for (int i = 0; i < n; i++) {
int temp;
cin >> temp;
numbers.push_back(temp);
}
dfs(0, 0);
numbers.clear();
lottos.clear();
cout << '\n';
}
return 0;
}
'알고리즘 > 문제풀이' 카테고리의 다른 글
BOJ 17839 - Baba is Rabbit 문제풀이 (0) | 2020.03.31 |
---|---|
BOJ 1929 - 소수 구하기 문제풀이 (0) | 2020.03.30 |
BOJ 1697 - 숨바꼭질 문제풀이 (0) | 2020.03.30 |
BOJ 1057 - 토너먼트 문제풀이 (0) | 2020.03.30 |
BOJ 2293 - 동전 1 문제풀이 (0) | 2020.03.27 |
댓글
이 글 공유하기
다른 글
-
BOJ 17839 - Baba is Rabbit 문제풀이
BOJ 17839 - Baba is Rabbit 문제풀이
2020.03.31 -
BOJ 1929 - 소수 구하기 문제풀이
BOJ 1929 - 소수 구하기 문제풀이
2020.03.30 -
BOJ 1697 - 숨바꼭질 문제풀이
BOJ 1697 - 숨바꼭질 문제풀이
2020.03.30 -
BOJ 1057 - 토너먼트 문제풀이
BOJ 1057 - 토너먼트 문제풀이
2020.03.30