> [!date] published: 2021-07-19
[3425번: 고스택](https://www.acmicpc.net/problem/3425)
## 🌟 문제
고창영은 스택을 조금 변형해서 고스택을 만들었다.
고스택은 숫자만을 저장할 수 있고, 다음과 같은 10가지 연산을 수행할 수 있다.
편의상 스택의 가장 위에 저장된 수를 첫 번째 수라고 하고, 그 다음은 차례대로 두 번째 수, 세 번째 수라고 한다.
- NUM X: X를 스택의 가장 위에 저장한다. (0 ≤ X ≤ 109)
- POP: 스택 가장 위의 숫자를 제거한다.
- INV: 첫 번째 수의 부호를 바꾼다. (42 -> -42)
- DUP: 첫 번째 숫자를 하나 더 스택의 가장 위에 저장한다.
- SWP: 첫 번째 숫자와 두 번째 숫자의 위치를 서로 바꾼다.
- ADD: 첫 번째 숫자와 두 번째 숫자를 더한다.
- SUB: 첫 번째 숫자와 두 번째 숫자를 뺀다. (두 번째 - 첫 번째)
- MUL: 첫 번째 숫자와 두 번째 숫자를 곱한다.
- DIV: 첫 번째 숫자로 두 번째 숫자를 나눈 몫을 저장한다. 두 번째 숫자가 피제수, 첫 번째 숫자가 제수이다.
- MOD: 첫 번째 숫자로 두 번째 숫자를 나눈 나머지를 저장한다. 두 번째 숫자가 피제수, 첫 번째 숫자가 제수이다.
자세한 문제 내용은 위의 문제 링크에서..
## 🌟 입력
입력은 기계 여러 대의 설명으로 이루어져 있다. 각 기계의 설명은 프로그램과 입력영역으로 나누어져 있다.
프로그램은 명령어로 이루어져 있고, 명령어는 한 줄에 하나씩 있다. 각 명령은 문제 설명에 나와있는 대문자 알파벳 3글자이고, 다른 글자는 주어지지 않는다. NUM의 경우에는 명령어 다음에 숫자가 주어지며, 이 숫자는 0보다 크거나 같고, 109보다 작거나 같은 정수이다. NUM과 숫자는 공백으로 구분되어져 있다. 각 프로그램은 END가 나오면 끝난다.
입력영역은 첫째 줄에 프로그램 수행 횟수 N이 있다. (0 ≤ N ≤ 10,000) 다음 N개의 줄에는 한 줄에 하나씩 입력값 Vi가 있다. (0 ≤ Vi ≤ 109) 각 입력값에 대해서 프로그램을 한 번씩 수행해야 하고, 이 수행은 모두 독립적이다. 매번 프로그램을 수행할 때, 스택에 들어있는 값은 입력값 Vi 하나이다.
각각의 기계 설명은 빈 줄로 구분되어져 있다. QUIT이 나오면 다음 기계 설명이 없다는 뜻이다. 명령어가 100,000개를 넘어가는 경우와 스택이 수행될 때, 1,000개 이상의 숫자를 저장하는 경우는 없다.
## 🌟 출력
각각의 입력값에 대해서, 해당하는 프로그램을 수행한 뒤, 출력값을 출력하면 된다. 출력값이란 스택에 저장되어 있는 숫자이다.
만약, 프로그램 에러가 발생하거나, 모든 수행이 종료됐을 때 스택에 저장되어 있는 숫자가 1개가 아니라면, "ERROR"를 출력한다.
각 기계에 대한 출력값을 모두 출력한 뒤에는 빈 줄을 하나 출력해야 한다.
## 🌟 풀이
문제가 길고 어려워 보이지만 그냥 주어진 연산자의 기능들을 그대로 구현해 주는 비교적 단순한 문제이다.
다른 블로그에서는 주어지는 오류에 관한 예외처리들에 신경을 써 주는 것이 핵심이라고 많이 적혀있었지만...
사실 나는 오류 처리보다는 문제 이해에 더 많은 시간을 쏟았다.
문제 입력 부분을 자세히 읽었어야 했다.;;
---
입력 설명에 보면 명령어 정보가 주어진 뒤에 입력되는 숫자가 **프로그램 실행 횟수**이다.
나는 멋대로 스택 내부의 숫자의 개수라고 생각해서 스택에 입력되는 숫자들을 모두 넣고 명령어를 실행하는 바람에 결과가 완전히 이상하게 나와 디버깅 하는데 시간이 엄청 들었다...
그러니까 입력영역에
```
3
1
10
50
```
이렇게 주어진다면 입력된 명령어 벡터를 총 3번을 실행시켜야 하는데 그 초깃값들이 각각 1, 10, 50인 것이다.
그리고 출력될 결괏값들은 스택에 원소가 딱 1개 있을때만 정상적으로 프로그램이 종료된 것으로 생각하고 그 원소의 값이 되는 것이다.
스택의 값을 출력해야 한다는 것만 읽고 비어있지 않은 한 스택의 모든 원소들을 출력하는 바람에... 또 디버깅 열심히 했다..
그리고 잊을 수도 있는 부분인데 (나는 이것때문에 제출을 3번이나 더 했다. 신중하게 제출하자...) 출력 설명에 _각 기계에 대한 출력값을 모두 출력한 뒤에는 빈 줄을 하나 출력해야 한다._ 라는 말이 있는데,
이 말은 각 프로그램, 즉 각 명령어 벡터에 해당되는 값들을 모드 실행시키고, 출력한 후에 다음 명령어로 넘어가기 전에 개행을 하나 출력하라는 뜻이었다..
역시 문제 이해부터가 시작이라는 것을 뼈저리게 느꼈고 앞으로는 좀 더 신중히 보기로 다짐했다.
---
이렇게 문제 중간중간 세세하게 신경써줘야 하는 부분 외에는 정말 단순 구현 문제라.. 문제를 찬찬히 읽고 그대로 구현해 보면 어렵지 않게 해결할 수 있을 것이다.
## 🌟 코드
```cpp
#include <iostream>
#include <string>
#include <stack>
#include <utility>
#include <vector>
using namespace std;
vector<pair<string, long long>> commands;
stack<long long> num_stack;
//abs 함수가 int만 사용할 수 있는 줄 알고 따로 abs 함수를 구현해서 사용했는데 long long 범위에서도 사용할 수 있는 듯 하다;;
long long labs(long long num){
if (num < 0)
return (num * (-1));
return (num);
}
// commands에 operator를 넣는 함수.
int input_op(){
string operation;
long long x;
cin >> operation;
while (operation != "END"){
x = 0;
if (operation == "QUIT")
return (0);
if (operation == "NUM")
cin >> x;
commands.push_back(make_pair(operation, x));
cin >> operation;
}
return (1);
}
// 여기서부터 각각의 연산자들에 대한 함수를 구현했다.
// 코드가 너무 길어져서 내부 구현은 생략합니다...
bool num(long long x);
bool pop();
bool inv();
bool dup();
bool swp();
bool add();
bool sub();
bool mul();
bool div();
bool mod();
// 에러가 발생했을 경우
void error(){
while (!num_stack.empty())
num_stack.pop();
cout << "ERROR" << '\n';
}
// commands의 연산들이 모두 완료된 경우
void print_result(){
if (num_stack.size() != 1)
error();
else{
cout << num_stack.top() << '\n';
num_stack.pop();
}
}
// 각 명령어에 맞춰서 연산자 함수를 호출하는 함수
void prog(){
for(int i = 0; i < commands.size(); i++){
if (commands[i].first == "NUM"){
if (num(commands[i].second) == false){
error();
return;
}
}
else if (commands[i].first == "POP"){
if (pop() == false){
error();
return;
}
}
else if (commands[i].first == "INV"){
if (inv() == false){
error();
return;
}
}
else if (commands[i].first == "DUP"){
if (dup() == false){
error();
return;
}
}
else if (commands[i].first == "SWP"){
if (swp() == false){
error();
return;
}
}
else if (commands[i].first == "ADD"){
if (add() == false){
error();
return;
}
}
else if (commands[i].first == "SUB"){
if (sub() == false){
error();
return;
}
}
else if (commands[i].first == "MUL"){
if (mul() == false){
error();
return;
}
}
else if (commands[i].first == "DIV"){
if (div() == false){
error();
return;
}
}
else if (commands[i].first == "MOD"){
if (mod() == false){
error();
return;
}
}
}
print_result();
}
int main(){
int temp, n;
long long templ;
while (1){
temp = input_op();
if (temp == 0)
break;;
cin >> n;
for (int i = 0; i < n; i++){
cin >> templ;
num_stack.push(templ);
prog();
}
commands.clear();
cout << '\n';
}
return (0);
}
```