개인사
[G1] 백준 16638번 괄호 추가하기 2 C++ 구현, 백트래킹 본문
728x90

리뷰

https://www.acmicpc.net/problem/16638
백트래킹으로 괄호를 배치하는 모든 경우를 찾고, 사칙 연산을 구현하여 최대값을 구하는 문제
전역 변수
- n : 수식의 길이를 저장할 변수
- s : 수식을 저장할 문자열
- op : 연산자를 저장할 배열
- num : 숫자를 저장할 배열
- c_op : 선택한 연산자를 저장할 벡터
- c_num : 선택한 숫자를 저장할 벡터
- ans : 정답을 저장할 변수
함수
1. bt
void bt(int level, bool prev) {
if (level >= n / 2) {
vector<int> temp(1, c_num[0]);
//cout << c_op.size() << " " << c_num.size() << "\n";
//cout << c_num[0];
//for (int i = 0; i < c_op.size(); ++i) cout << c_op[i] << c_num[i + 1];
//cout << "\n";
for (int i = 0; i < c_op.size(); ++i) {
//cout << temp.back() << "\n";
if (c_op[i] == '+') temp.push_back(c_num[i + 1]);
else if (c_op[i] == '-') temp.push_back(-c_num[i + 1]);
else temp.back() *= c_num[i + 1];
}
//cout << temp.back() << "\n";
int sum = 0;
for (int i : temp) sum += i;
//cout << sum << "\n";
ans = max(ans, sum);
return;
}
int a = num[level + 1];
char b = op[level];
if (!prev) {
int c = c_num.back(); c_num.pop_back();
if (b == '+') c_num.push_back(c + a);
else if (b == '-') c_num.push_back(c - a);
else c_num.push_back(c * a);
bt(level + 1, true);
c_num.pop_back();
if (b == '+') c_num.push_back(c);
else if (b == '-') c_num.push_back(c);
else c_num.push_back(c);
}
c_num.push_back(a);
c_op.push_back(b);
bt(level + 1, false);
c_num.pop_back();
c_op.pop_back();
}
괄호를 배치하거나 배치하지 않는 경우를 분기처리하고, 기저 조건에서 연산을 수행 후 ans를 최신화 하는 함수
문제풀이
- n, s값을 입력 받고, s를 순회하며 연산자는 op배열에, 숫자는 num배열에 저장한다.
- c_num에 초기 숫자인 num[0]을 추가한다.
- bt함수에 0, false를 매개변수로 전달하여 함수를 호출한다.
- bt함수는 변수 level, prev에 매개변수를 전달받아 파싱한다.
- 기저 조건으로 level이 n/2에 도달했다면, 정수형 벡터 temp를 c_num[0]을 넣은 상태로 초기화하고, c_op를 순회한다.
- 연산자가 '+'라면 temp에 다음 숫자를 추가한다.
- 연산자가 '-'라면 temp에 다음 숫자를 음수로 추가한다.
- 연산자가 '*'라면 temp의 맨 뒷 요소에 다음 숫자를 곱한다.
- 변수 sum을 0으로 초기화 하고, temp를 순회하며 각 요소를 sum에 더해준다.
- ans를 sum과 비교하여 더 큰 값으로 최신화 하고, 리턴 처리한다.
- 기저 조건에 해당하지 않는다면 변수 a에 다음 숫자를, b에 다음 연산자를 저장한다.
- prev가 false라면 괄호를 씌우는 로직을 실행 후 재귀를 수행하고, 재귀를 빠져나오며 원상 복구를 해준다.
- 괄호를 씌우지 않는 로직도 실행 후 재귀를 수행하고, 재귀를 빠져나오며 원상 복구를 해준다.
- bt함수가 종료된 후 ans에 저장된 값을 출력한다.
트러블 슈팅
- 구현을 완료하고 예제 테스트 시 4번에서 에러가 발생하였다.
- 괄호를 씌우는 과정에서 c_num의 back()에 바로 연산처리한 것이 원인이었다.
- 0을 곱하는건 문제가 없지만 원상 복구를 해줄때 0으로 나누는 경우가 있어서 DivideZero에러가 발생한 듯 하다.
- 별도의 변수 c에 c_num의 back()을 저장하고 pop처리 후 안전하게 처리해주어 AC를 받았다.
참고 사항
- 중첩된 괄호는 사용할 수 없다는 조건으로 인해 prev를 사용해 연속으로 괄호를 사용할 수 없게 구현하였다.
- 음수가 정답으로 나올 수 있으므로 ans의 초기값은 매우 작은 음수로 설정해주었다.
정답 코드
#include<iostream>
#include<vector>
using namespace std;
int n;
string s;
char op[10];
int num[11];
vector<char> c_op;
vector<int> c_num;
int ans = -2e9;
void bt(int level, bool prev) {
if (level >= n / 2) {
vector<int> temp(1, c_num[0]);
//cout << c_op.size() << " " << c_num.size() << "\n";
//cout << c_num[0];
//for (int i = 0; i < c_op.size(); ++i) cout << c_op[i] << c_num[i + 1];
//cout << "\n";
for (int i = 0; i < c_op.size(); ++i) {
//cout << temp.back() << "\n";
if (c_op[i] == '+') temp.push_back(c_num[i + 1]);
else if (c_op[i] == '-') temp.push_back(-c_num[i + 1]);
else temp.back() *= c_num[i + 1];
}
//cout << temp.back() << "\n";
int sum = 0;
for (int i : temp) sum += i;
//cout << sum << "\n";
ans = max(ans, sum);
return;
}
int a = num[level + 1];
char b = op[level];
if (!prev) {
int c = c_num.back(); c_num.pop_back();
if (b == '+') c_num.push_back(c + a);
else if (b == '-') c_num.push_back(c - a);
else c_num.push_back(c * a);
bt(level + 1, true);
c_num.pop_back();
if (b == '+') c_num.push_back(c);
else if (b == '-') c_num.push_back(c);
else c_num.push_back(c);
}
c_num.push_back(a);
c_op.push_back(b);
bt(level + 1, false);
c_num.pop_back();
c_op.pop_back();
}
int main() {
cin >> n >> s;
for (int i = 0; i < n; ++i) {
if (i % 2) op[i / 2] = s[i];
else num[i / 2] = s[i] - '0';
}
c_num.push_back(num[0]);
bt(0, false);
cout << ans;
}728x90
'알고리즘 공부 > C++' 카테고리의 다른 글
| [G5] 백준 5588번 별자리 찾기 C++ 브루트포스 알고리즘, 해시 집합, unordered_set (0) | 2025.11.25 |
|---|---|
| [G3] 백준 20440번 🎵니가 싫어 싫어 너무 싫어 싫어 오지 마 내게 찝쩍대지마🎵 - 1 C++ 정렬, 값/좌표 압축, 누적합, 차분 배열 트릭 (0) | 2025.11.22 |
| [G4] 백준 22945번 팀 빌딩 C++ 투 포인터 (0) | 2025.11.21 |
| [G5] 백준 9024번 두 수의 합 C++ 투 포인터, 정렬 (0) | 2025.11.21 |
| [G4] 백준 16929번 Two Dots C++ 깊이 우선 탐색 (0) | 2025.11.21 |
