1233. 사칙연산 유효성 검사
Code Battle (`23 동계 대학생 S/W 알고리즘 특강 기초학습 문제)
본 게시글은 개인 학습 용도로 작성한 게시글입니다.
(문제 출처: SW Expert Academy)
- 분할 정복 + 트리 순회 (post-order) 문제.
- 완전 이진 트리이므로, 배열로 트리 구현이 가능하다.
- 노드 번호와, 자식 노드의 번호는 예측 가능하므로 입력받지 않고 무시하였다.
cin.ignore()
사용. - 재귀호출을 이용하여 post order 순회를 구현하였다.
- 어떤 노드에서 해당 식이 유효한 지 검사하는 방법은 다음과 같다:
- 1. 어떤 노드의 자식이 하나도 없다면, 해당 노드는 숫자여야만 유효한 식이 된다.
- 2. 어떤 노드의 자식이 하나만 있다면, 피연산자가 모자라서 식이 완성되지 못하므로 유효하지 않은 것이다.
- 3. 어떤 노드의 자식이 둘 다 있다면, 두 자식 모두 1, 2, 3 중 하나에 대하여 유효한 식이어야 한다.
- 위의 검사를 재귀적으로 수행하면 분할 정복 문제로서 이 문제를 풀이 할 수 있다.
#include <cctype>
#include <string>
#include <iostream>
#define MAX_N 200
#define ANSWER_POSSIBLE 1
#define ANSWER_IMPOSSIBLE 0
using namespace std;
int treeSize;
char tree[MAX_N + 1];
int left(int i)
{
return i << 1;
}
int right(int i)
{
return (i << 1) + 1;
}
bool has(int i)
{
return i <= treeSize;
}
bool is_leaf(int i)
{
return !has(left(i));
}
bool has_both_children(int i)
{
return has(left(i)) && has(right(i));
}
bool post_order(int i)
{
if (is_leaf(i))
{
return isdigit(tree[i]); // Leaf 노드는 항상 숫자여야함.
}
if (has_both_children(i))
{
return post_order(left(i)) && post_order(right(i));
}
return false; // 피연산자가 하나 밖에 없으면 불가능.
}
static int solve()
{
int i;
cin >> treeSize;
cin.ignore();
for (i = 1; i <= treeSize; i++)
{
cin.ignore(4, ' ');
cin >> tree[i];
cin.ignore(16, '\n');
}
return post_order(1) ? ANSWER_POSSIBLE : ANSWER_IMPOSSIBLE;
}
int main(int argc, char **argv)
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
for (int test_case = 1; test_case <= 10; ++test_case)
{
printf("#%d %d\n", test_case, solve());
}
return 0;
}