티스토리 뷰

문제 링크입니다 : https://www.acmicpc.net/problem/16637

 

16637번: 괄호 추가하기

첫째 줄에 수식의 길이 N(1 ≤ N ≤ 19)가 주어진다. 둘째 줄에는 수식이 주어진다. 수식에 포함된 정수는 모두 0보다 크거나 같고, 9보다 작거나 같다. 문자열은 정수로 시작하고, 연산자와 정수가

www.acmicpc.net

 

생각보다 좀 어려운 문제였다.

문제를 보고 처음에는 이전 데이터를 계산하는 과정이 있어서 스택으로 해결할 수 있는 방법이 없나 고민했다. 하지만 스택으로 경우 수를 나누기엔 경우의 수가 너무 많았다.

 

 그래서 문제를 다시 천천히 보니 입력 N이 최대 19로 굉장히 작았다. 그럼 19가 입력의 최대 길이라면 그 중 연산자는 최대 9개가 되므로 9!를 했을 때 연산 과정이 362,880이 된다. 충분히 연산 가능하다. 그리고 괄호를 이중으로 못 친다는 조건으로 백트래킹하면 실제 연산은 더 적어진다.

 

구현은 재귀함수로 구했다.

 

 

입력이 충분히 작다면 최우선적으로 브루트포스를 고려하자.

 

 

#include <iostream>
#include <vector>
#include <algorithm>
#define INF 987654321

using namespace std;

int ret = -INF;

// 부호에 맞게 계산해주는 함수
int calc(int a, int b, char c) {
    switch(c) {
        case '+':
            return a + b;
        break;
        case '-':
            return a - b;
        break;
        case '*':
            return a * b;
        break;
    }
    return -INF;
}


// 재귀적으로 호출하면서 괄호를 묶어본다.
void getCnt(const vector<pair<int, bool>>& num, const vector<char>& oper) {

    // 연산 없이 숫자 1개짜리만 들어올 경우가 있다.
    // 그런 경우도 그냥 리턴하면 안되므로 if부분을 넣어주었다.
    if(num.size() == 1) {
        if(num[0].first > ret) ret = num[0].first;
        return;
    }
    

    // 연산자 숫자 만큼 순회하며 괄호를 묶어본다.
    for(int i = 0; i < oper.size(); i++) {

        //이전에 연산되어 만들어진 숫자들은 건너 뛴다.
        if(num[i].second) continue;
        if(num[i + 1].second) continue;

        // 시도를 하더라도 데이터는 보존해야 하므로 새로 만든다.
        // 괄호로 묶어서 계산하면 숫자 갯수가 2개에서 1개로 줄어 듦으로
        // iterator를 만든다.
        // ex) A + (B * C) - D 이 경우 B와 C가 연산되어 하나의 숫자가 된다.
        // A + (?) - D 이런식으로.. 그래서 한 자리를 지운다.
        vector<pair<int, bool>> tempNum = num;
        vector<char> tempOper = oper;
        vector<pair<int, bool>>::iterator numIter = tempNum.begin();
        vector<char>::iterator operIter = tempOper.begin();

        // 괄호쳐서 연산해보기, 그리고 연산했으면 true로 처리해서 다시는 괄호로 못 묶게 한다.
        tempNum[i + 1].first = calc(tempNum[i].first, tempNum[i + 1].first, tempOper[i]);
        tempNum[i + 1].second = true;
        
        // 괄호쳐서 만들어진 숫자는 하나이므로 괄호 안에 있던 숫자 두개 중 왼쪽에 있는 숫자를 지운다.
        numIter += i;
        operIter += i;
        tempNum.erase(numIter);
        tempOper.erase(operIter);

        // 괄호를 더 만들 수 있다고 하더라도, 더 안 만들어야 커지는 경우도 있다.
        int sum = tempNum[0].first;
        for(int i = 0; i < tempOper.size(); i++) {
            sum = calc(sum, tempNum[i + 1].first, tempOper[i]);
        }


        getCnt(tempNum, tempOper);
        
        if(sum > ret) ret = sum;

    }


}


int main() {

    int N;
    cin >> N;

    string str;
    cin >> str;

    vector<pair<int, bool>> num(str.size() / 2 + 1);
    vector<char> oper(str.size() / 2);
    int numIdx = 0;
    int operIdx = 0;
    for(int i = 0; i < str.size(); i++) {
        if(i % 2 == 1) {
            oper[operIdx++] = str[i];
        } else {
            num[numIdx].second = false;
            num[numIdx++].first = str[i] - '0';
        }
    }

    getCnt(num, oper);
    
    cout << ret;

    return 0;
}

 

 

 

 

개발 환경 : vscode

지적, 조언, 질문 환영입니다! 댓글 남겨주세요~

 

 

 

'알고리즘 > 백준(BOJ)' 카테고리의 다른 글

백준 - 11286 절대값 힙  (0) 2020.06.11
백준 - 1927 최소 힙  (0) 2020.06.11
백준 - 1600 말이 되고픈 원숭이  (0) 2020.06.04
백준 - 14948 군대탈출하기  (5) 2020.06.02
백준 - 2194 유닛 이동시키기  (0) 2020.05.03
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2025/04   »
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
글 보관함