문제 링크
https://www.acmicpc.net/problem/1107
알고리즘 유형
브루트 포스
시간복잡도
브루트 포스의 시간 복잡도는 \(O(경우의\ 수\times 각\ 경우의\ 시간\ 복잡도)\)
경우의 수
리모컨에는 버튼이 0부터 9까지 숫자, +와 -가 있다. 어떤 버튼이 고장났는지 주어졌을 때, 채널 N으로 이동하기 위해서 버튼을 최소 몇 번 눌러야하는지 구하는 프로그램을 작성하시오.
숫자 버튼 선택
숫자 버튼으로 주어진 채널 N과 가장 가까운 채널을 생성해야 한다.
고장난 버튼을 제외하는 시점에 따라 2가지 방법 존재
- 고장난 버튼을 제외하고 채널 생성
- 생성된 채널 중 고장난 버튼 포함하는 채널 제외
두 방법 모두 고장난 버튼이 없을 경우 0 ~ 9 모든 버튼으로 생성할 수 있는 채널 N개를 모두 생성해야 한다.
여기까지의 시간 복잡도는 \(O(N)\)이다.
하지만 2번의 경우 생성된 채널의 각 자리수가 고장난 버튼인지 확인해야 한다.
N에는 총 \(logN\)의 자리수가 존재하기 때문에 2번의 시간복잡도는 \(O(N \times logN = NlogN)\)이다.
시간복잡도가 낮은 1번을 채택한다.
+/- 버튼 선택
숫자 버튼으로 생성한 채널에서 N까지 거리만 구하면 된다. 따라서 시간복잡도는 O(1)
각 경우의 시간 복잡도
별도 요구되는 연산 없음
총 시간 복잡도
\(O(N \times 1 = N)\)
코드
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int N, M;
bool err_dgt[10];
vector<int> dgts;
int chl_len;
int answer;
void bf(int pos, int chl){
// 숫자 버튼을 1회 이상 눌렀다면 생성된 채널과 N의 거리의 최솟값 갱신
if (pos) {
answer = min(answer, pos + abs(N - chl));
}
// 주어진 채널보다 자리수가 1 더 긴 채널까지만 생성한다.
if (pos > chl_len) return;
// 이번 자리수 선택
for (int dgt : dgts) {
bf(pos + 1, chl * 10 + dgt);
}
}
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> N >> M;
for (int i = 0; i < M; ++i) {
int dgt;
cin >> dgt;
err_dgt[dgt] = true;
}
// 사용할 수 있는 자리수의 벡터 dgts 초기화
for (int dgt = 0; dgt < 10; ++dgt) {
if (err_dgt[dgt]) continue;
dgts.push_back(dgt);
}
// 정답의 초기값은 숫자 버튼을 누르지 않는 경우
answer = abs(N - 100);
// 숫자 버튼을 눌러서 채널 생성
chl_len = to_string(N).size();
bf(0, 0);
cout << answer;
return 0;
}
PREVIOUSBOJ 2309 일곱 난쟁이
NEXTBOJ 3085 사탕 게임