2471. 모빌 이진수 : https://www.acmicpc.net/problem/2471
2471번: 모빌 이진수
첫째 줄에는 0, 1과 괄호들로 구성된 모빌의 상태 표현이 주어진다. 모빌의 상태 표현은 빈칸 없이 이어진 문자열로 주어진다. 주어지는 0, 1과 괄호들의 총 개수는 200개 이하이다. 둘째 줄에는 K
www.acmicpc.net
문제 파악하기
- 0과 1로 이루어진 이진수가 주어집니다.
- 괄호 안의 값은 회전할 수 있으며, 회전 시 괄호 안의 숫자들은 뒤집히게 됩니다.
- 주어진 이진수로 만들 숫자 중 K번째 숫자를 찾아야 합니다.
- 입력되는 숫자와 괄호의 길이는 최대 200개이기 때문에 문자열로 입력을 받아야 합니다.
- 메모리의 제한 때문에 만들 수 있는 모든 문자열을 저장할 수는 없습니다.
- 그럼 메모리를 절약할 수 있는 방법은 어떤 것이 있을까요?
문제 해결하기
- 우선순위 큐(priority_queue)를 사용하면 메모리를 절약할 수 있습니다.
- 우선순위 큐를 사용하면 가장 높은 우선순위를 가진 문자열 혹은 이진수가 나오게 됩니다.
[ 우선순위 : 길이 >> 괄호 >> 0 >> 1 ] - 문자열이 나온 경우 괄호를 왼쪽에서부터 하나씩 제거하고 나올 수 있는 이진수를 모두 우선순위 큐에 저장합니다.
>> 기존 순서를 유지한 이진수 / 제거한 괄호 안의 값을 회전시킨 이진수 - 큐에 저장할 때에는 해싱(map)을 사용해 중복된 문자열이 나온 경우 입력을 제거해야 합니다.
- 이진수가 나온 경우, K의 값을 감소시킵니다. 만약 K의 값이 0이 된다면 탐색을 종료합니다.
소스코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <map>
using namespace std;
string inp;
int k, len;
string top;
map< string, int > check;
priority_queue< string, vector< string >, greater< string > > pq;
char convert(char c) {
if(c == '(') return ')';
else if(c == ')') return '(';
else return c;
}
void makeNum(string s) {
int cnt=0;
string str;
int st, ed, f=0;
// 가장 먼저 시작하는 괄호만 제거해서 넣기
str.clear();
for(char c:s) {
// 제거할 괄호를 찾은 후에는 그대로 복사
if(f) str.push_back(c);
else {
if (c == '(') {
if (cnt > 0) str.push_back(c);
cnt++;
// 가장 왼쪽 괄호의 시작부분
if (cnt == 1) st = str.length();
}
else if (c == ')') {
// 가장 왼쪽 괄호의 종료부분
if (cnt == 1) {
ed = str.length() - 1;
f = 1;
}
cnt--;
if (cnt > 0) str.push_back(c);
}
else {
str.push_back(c);
}
}
}
// 기존 문자열 중복 확인하기
if(!check[str]) {
pq.push(str);
check[str] = 1;
}
// 가장 왼쪽에 위치한 괄호 회전시킨 후 저장하기
while(st <= ed) {
// 괄호인 경우, 방향을 바꿔주어야 함 >> convert함수
char tmp = convert(str[st]);
str[st] = convert(str[ed]);
str[ed] = tmp;
st++; ed--;
}
// 회전한 문자열 중복 확인하기
if (!check[str]) {
pq.push(str);
check[str] = 1;
}
}
int main() {
// 입력
cin >> inp;
cin >> k;
// 숫자 개수 세기
for(char c:inp) {
if(c=='0' or c=='1') len++;
}
// 우선순위 큐를 사용한 탐색
pq.push(inp);
while(!pq.empty() and k>0) {
top = pq.top();
pq.pop();
// 숫자인 경우에만 K값 감소
if(top.length() == len) k--;
else makeNum(top);
}
// 출력
if(k == 0) cout << top;
else cout << "NO";
}
|
cs |
후기
어느정도 난이도가 있는 문제라고 생각합니다. 우선순위 큐를 활용하는 것은 어렵지 않지만 알고리즘을 떠올리는데 난이도가 있는 문제입니다. 자료구조에 대한 공부를 하기 위해 추천하는 문제입니다.
'문제 노트 > 정올' 카테고리의 다른 글
나누기( BOJ 21757 ) (0) | 2021.10.21 |
---|---|
절사평균( BOJ 6986 ) (0) | 2021.09.27 |
배수( BOJ 2595 ) (0) | 2021.08.31 |
양팔 저울( BOJ 1653 ) (0) | 2021.04.13 |
체인점( BOJ 2472 ) (0) | 2021.03.13 |