두 번째로 케이스워크(Case Work)에 대해서 살펴보기로 한다. 케이스워크라는 단어는 PS를 오랫동안 했다면 별다른 어색함 없이 받아들이기 쉽지만, 자세히 생각해 보면 꽤 묘한 단어이다.
먼저 케이스(Case)는 직관적으로 번역할 수 있다. 여러 가지 경우를 말하는 것이다. 다음으로 워크(Work)의 간단한 번역 중 가장 나은 것은 '처리'라고 할 수 있다. 즉 케이스워크를 풀어서 설명하면 여러 가지 경우를 처리하는 것이 된다.
그러면 '여러 가지 경우'가 어느 정도를 의미하는지 생각해 보자. '여러 가지'는 추상적인 단어이기 때문에 이것을 모든 사람이 동일하게 받아들이도록 정의할 수는 없다. 대신 다수의 사람들이 동의할 만한 기준을 세울 수는 있다. 예를 들어 이런 문제가 케이스워크에 해당하는지 묻는다면 아니라고 답하는 사람이 많을 것이다.
두 정수 $A$와 $B$가 주어졌을 때, $A$와 $B$를 비교하는 프로그램을 작성하시오.
반면 이런 문제가 케이스워크에 해당하는지 묻는다면 그렇다고 답하는 사람이 많을 것이다.
$4$개의 주사위를 굴려서 규칙에 맞게 상금을 받을 때, 가장 많은 상금을 받은 사람의 상금을 구하시오.
첫 번째 문제에서 $A$와 $B$의 대소를 비교하면 세 가지 경우가 나올 수 있고, 두 번째 문제에서는 주사위를 굴린 결과를 다섯 가지로 구분한다. 분명 두 번째 문제에서 처리해야 할 케이스가 더 많은 것은 사실이지만, 단순히 이 이유만으로 사람들이 케이스워크 문제라고 인식하는 건 아니다. 이런 문제를 예로 들어 보자.
스코어보드와 등수가 주어질 때, 그 등수의 팀이 해결한 문제 수와 그 팀의 페널티를 구하시오.
등수의 범위는 $1$ 이상 $11$ 이하이므로 처리해야 하는 케이스는 $11$가지이다. 하지만 난이도 투표를 열어보면 이 문제를 케이스워크로 인식하는 사람은 그렇게 많지 않다. 물론 정답 문자열을 리스트에 다 저장해 놓는 방식으로 구현하면 조건문을 안 쓰고도 풀 수 있어서 그렇기도 하지만, 그것보다 더 중요한 이유는 이 문제에서 케이스를 나누는 기준과 각 케이스를 처리하는 방법 양쪽이 모두 매우 간단한 형태로 되어 있기 때문이다. 즉, 많은 사람들이 케이스워크라고 인식하는 문제들은 대부분 다음 두 가지 특징을 갖는다는 것을 알 수 있다.
- 문제의 티어에서 예상 가능한 정도보다 많은 수의 케이스가 등장한다.
- 각각의 케이스를 분류하는 기준과 케이스들을 처리하는 방법이 충분히 덜 단순한 형태로 되어 있다.
모든 사람이 받아들일 만한 기준을 제시하지 않기 때문에 두 가지 특징 역시 덜 구체적으로 명시되었다.
다음으로 처리해야 하는 케이스가 많을 때 어떻게 하면 좀 더 편하게, 그리고 실수 없이 구현할 수 있는지 살펴보기로 한다. 기본적으로 케이스워크를 할 때는 코드가 간단할수록 좋은데 코드는 그냥 구현한다고 해서 간단해지지 않는다. 먼저 다음 문제를 보자.
BOJ 15873. 공백 없는 A+B (Bronze IV)
자연수 $A$, $B$가 주어지면 $A+B$를 구하는 프로그램을 작성하시오.
$A$와 $B$는 $1$ 이상 $10$ 이하의 정수인데, 공백으로 구분되지 않고 붙어서 입력된다. 따라서 입력된 문자열에서 $A$와 $B$를 구분하는 지점이 어디인지 찾아야 한다.
여기서 가장 쉽게 생각할 수 있는 케이스 구분 방법은 입력의 길이를 이용하는 것이다. 입력의 길이가 늘어나는 경우는 $10$이 입력될 때뿐이므로 입력의 길이가 $2$이면 $A$와 $B$가 둘 다 $9$ 이하이고, 길이가 $3$이면 둘 중 하나만 $10$이고, 길이가 $4$이면 둘 다 $10$이다. 따라서 길이가 $2$인 경우는 한 글자씩 잘라서 정수 덧셈을 하면 되고, 길이가 $4$인 경우는 $20$이 답이 된다. 길이가 $3$인 경우 $A$가 $10$일 수도 있고 $B$가 $10$일 수도 있는데, 입력되는 수 중에서 문자 $0$을 포함하는 수가 $10$밖에 없으므로 $0$의 위치가 어디인지 확인하면 두 수를 모두 알아낼 수 있다.
BOJ 25285. 심준의 병역판정검사 (Bronze III)
문제를 하나 더 보자. 신장과 체중을 입력받아서 등급을 구하는 문제이다. (참고로 문제에 나온 표는 최신 버전이 아니다.) 이 문제에서 어떻게 케이스 처리를 하는 게 좋을지 알아보자. 이 문제에서 나오는 척도에는 신장, 체중, BMI, 신체 등급이 있으므로 다음과 같은 방법들을 생각해 볼 수 있다.
- 신체 등급을 기준으로 케이스 처리를 한다. → 각각의 등급마다 '(신장 부등식) AND (BMI 부등식)' 절이 OR로 여러 개 묶여서 조건문에 들어가게 된다. 열심히 타이핑하면 되겠지만 뭔가 지저분한 느낌을 받기 쉬울 것이다.
- 체중을 기준으로 케이스 처리를 한다. → 표를 보면 알겠지만 일단 체중을 통해서 BMI를 구한 다음 거기서 다시 등급을 구하게 되어 있기 때문에 체중을 기준으로 케이스 처리를 하려면 각각의 체중에 대해 등급 구분의 기준이 되는 신장들을 식으로 나타낸 다음 케이스 처리를 해야 한다. 이런 방법이 깔끔하다고 생각하는 사람은 아마 없을 것이다.
- BMI를 기준으로 케이스 처리를 한다. → 각각의 BMI 범위마다 특정 신장들을 기준으로 등급을 분류하면 된다. 확실히 앞의 두 방법보다는 더 간단하다.
- 신장을 기준으로 케이스 처리를 한다. → 각각의 신장 범위마다 특정 BMI들을 기준으로 등급을 분류하면 된다. 이것도 신체 등급이나 체중을 기준으로 하는 방법보다는 간단하다.
따라서 BMI나 신장을 기준으로 케이스 처리를 하는 게 좋다는 것을 알 수 있다. 그리고 이 두 방법에도 차이가 있으므로 그것을 한번 확인해 보자.
- BMI를 기준으로 케이스 처리를 할 경우, 처리해야 하는 구간은 $7$개이고, 각각의 BMI 구간마다 등급이 변하는 기준이 되는 신장들을 찾아서 처리하면 된다.
- 신장을 기준으로 케이스 처리를 할 경우, 처리해야 하는 구간은 $6$개이고, 각각의 신장 구간마다 등급이 변하는 기준이 되는 BMI들을 찾아서 처리하면 된다.
얼핏 보면 비슷해 보이지만 실제로는 큰 차이가 있는데, 신장을 기준으로 케이스 처리를 할 경우 $6$개 구간 중 $4$개는 구간 전체가 같은 등급 판정을 받기 때문에 실제로 BMI에 따라 다시 처리해야 하는 구간은 $2$개만 남는다. 반면 BMI를 기준으로 케이스 처리를 할 경우 모든 구간에서 전부 신장에 따라 다시 처리를 해야 한다는 번거로움이 생긴다. 따라서 신장을 기준으로 케이스 처리를 하는 것이 가장 간단하다고 할 수 있다. 여기서 '조건과 처리 방식이 모두 간단한 케이스는 먼저 처리하면 편하다'는 사실을 확인할 수 있다. 만약 남은 케이스 중에 그런 것이 없다면 처리 방식은 각자의 성향에 따라 다르겠지만, 개인적으로는 조건이 간단해지도록 케이스를 분류하는 것이 덜 헷갈려서 편한 것 같다.
[연습문제]
규칙에 맞게 상금을 계산하면 된다.
이번에도 규칙에 맞게 게임의 결과를 구하는 문제인데, 규칙이 좀 더 복잡하다.
두 직사각형의 겹치는 부분이 어떤 형태인지 파악하면 된다. 구현하기에 앞서 어떤 케이스를 먼저 처리하는 게 편할지 생각해 보자.
$1$의 개수를 세서 딸기와 토마토가 같이 자라는 칸이 없는 경우를 먼저 처리해 주면 간단해진다. 겹치는 칸이 있는 경우 씨앗 줄이 수직으로 교차해서 한 칸에서 만나거나, 아니면 같은 줄의 여러 칸에서 겹치게 된다. 두 가지 경우를 잘 구분해 주면 된다.
어떤 경우를 먼저 처리하는 게 쉬울지 고민하면서 잘 구현해 보자.
'Algorithm > K. Others' 카테고리의 다른 글
226. Offline Query (1) | 2025.04.09 |
---|---|
213. IMOS Method (4) | 2025.01.18 |
210. Two Pointers (0) | 2024.10.08 |
209. Coordinate Compression (0) | 2024.08.20 |
208. Others Intro (2) | 2024.08.12 |