문제
https://www.acmicpc.net/problem/15650
시간 제한 | 메모리 제한 | solved.ac 티어 |
1초 | 512MB | 실버 3 |
풀이
이 문제를 무작정 중첩반복문으로 풀기에는 어려워보인다. 중첩반복문을 쓰게되면 시간복잡도의 문제도 생기지만, 그 전에 몇번 중첩해야할지가 애매해진다. 숫자를 M개를 선택해야하는데, 이는 단순하게 생각해서 M중첩 반복문이 필요하다는 뜻이 될테니 말이다. 따라서 반복문만 사용하는 것이 아닌, 재귀함수와 섞어, 어떤 숫자를 선택했을때, 그 뒤의 숫자부터 다시 탐색하도록 작성하였다. 그러기 위해 제일 최근에 선택한 숫자가 무엇인지, 지금 몇개를 선택했는지를 재귀하면서 넘겨주고, 항상 이전에 선택한 숫자보다 더 큰 숫자부터 다시 탐색을 하는 방식을 선택하였다. 답을 출력하기 용이하도록 답을 문자열로 구성해나갔다.
이런 류의 문제를 백트래킹 알고리즘이라고 한다. 그런데 아직 백트래킹을 정확히 뭐라고 설명해야할지 잘 모르겠다. 기본골자는 브루트포스인데, 여기서 더 탐색해봤자 해가 아니거나 최적해가 아닌게 자명하다면 더 탐색하지 않는 방식으로 탐색의 숫자를 줄여나가면서도, 완전탐색의 강력함을 챙기는 알고리즘인거 같다. 솔직히 아직 감이 잘 잡히진 않는데, 내 풀이를 백트래킹에 끼워넣어보자면, 입력이 8 4이라고 해보자. 우리는 1~8에서 4개를 뽑아야 한다. 그리고 우리는 2와 4를 골라둔 상태이다. 여기서 우리는 1~4는 골라봤자 답이 아니라는걸 알 수 있다. 중복이어선 안되고, 오름차순으로 정렬되어야 하는데, 2와 4 다음에 1이 올수도 없을 뿐더러, 1 2 4 @ 라는 답은 이전에 1을 고른 후 재귀했을때 이미 찾았을 것이기 때문이다. 우리는 이전에 선택한 값을 재귀함수의 인자로 넘겨줬기 때문에 이 값보다 작거나 같은 값은 답이 될 수 없다는 것을 자명하게 알 수 있기 때문에 탐색하지 않는 것이다.
솔직히 백트래킹에 대해서 몇문장 쓰고, 내 문제가 어디에서 백트래킹을 쓴걸까하고 끼워맞추면서 써본거다. 맞을수도 있고 아닐수도 있다.
코드
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int n, m;
void sol(int prev, int cnt, string output) {
if (cnt == m) {
cout << output << endl;
}
for (int i = prev + 1; i <= n; i++) {
sol(i, cnt + 1, output + to_string(i) + " ");
}
}
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n >> m;
sol(0, 0, "");
}
'coding_test > BAEKJOON' 카테고리의 다른 글
백준 15652번 C++ 풀이 (0) | 2025.01.17 |
---|---|
백준 6593번 C++ 풀이 (0) | 2025.01.16 |
백준 2473번 C++ 풀이 (0) | 2025.01.15 |
백준 2467, 2470번 C++ 풀이 (0) | 2025.01.15 |
백준 1019번 C++ 풀이 (0) | 2025.01.15 |