[Coding Test] 최대 상금 (SWEA: 1244)
최대 상금 (SWEA: 1244)
최대 상금 문제는 주어지는 문자열의 자릿수를 교환해 최대 숫자를 만드는 문제입니다. 이때, 교환할 수 있는 횟수가 주어지며, 해당 숫자를 모두 소진해야 합니다.
Brute Force
완전 탐색은 여러 방법으로 구현될 수 있습니다. 이번 문제에서는 DFS를 활용했습니다. 이 DFS 함수를 설계할 때, 한 가지 기억해두면 좋은 것이 있습니다.
재귀함수는 귀납적 논증 과정을 닮았다는 것입니다. 우리는 내가 작성한 함수가 최대 값을 반환하는가?
를 고민할 필요 없습니다. 간단히 설명하기 위해 아래와 같이 간단한 코드를 작성합니다.
int dfs(int a, int b, int c){
// 최대 값 반환
if(a == b){
return c
}
/*
... specific operation
*/
int ret = dfs(a + 1, b, c);
ret = (ret > c) ? ret : c;
return ret;
}
dfs()
함수가 반환하는 값을 ret
변수에 저장합니다. 그런데 이 값과 우리가 비교하려는 값을 비교해 더 큰 값을 저장합니다. 즉, 이 과정에서 반환되는 값은 무조건 더 큰 값을 취하는 것을 보장할 수 있습니다.
따라서 반환되는 값이 실제 최대 값인지? 에 대한 고민은 필요 없으며, 반복적으로 발생하는 간단한 동작을 설계하는 것만으로도 구하려는 값이 최종적으로 반환됨을 확신할 수 있습니다.
아래 소스코드에서도 solve()
함수를 통해 그 개념을 더 자세히 익혀보면 좋을 것 같습니다.
여기서 한 가지 팁이 있습니다. int &ret = DP[cnt][number]
입니다. 바로 ret
변수가 DP[cnt][number]
를 가리키도록 한 것입니다. C++ 에서만 사용 가능한 것으로 Reference라 불립니다.
포인터와 다르게 레퍼런스에는 포인터 값을 한 번 밖에 할당 가능합니다. 새로운 포인터 재할당이 발생하면 에러를 반환합니다.
그 밖에도 여러 차이점이 존재하는데, 이곳을 확인하면 더 자세히 알 수 있습니다.
중요하게 생각할 점은 ret
값에 반환값, 최대값 등이 할당되면 동시에 이 레퍼런스가 가리키고 있는 값도 함께 변화한다는 것입니다.
코딩 테스트 중간중간 여러 곳에서 발생하는 Memoization Cache 변화를 추적할 필요 없습니다. 위와 같은 선언 한 번으로 아래에서 발생하는 모든 경우를 커버할 수 있습니다.
소스 코드
#include<iostream>
#include<cstring>
using namespace std;
int parse_int(char*);
int length_of_str(char*);
int length_of_int(int);
int solve(int, int);
int swap_int(int, int, int);
int cache[11][1000000];
int main(int argc, char** argv) {
//freopen("sample_input.txt", "r", stdin);
int T, test_case;
cin >> T;
char numberString[7];
int trial_cnt;
for (test_case = 1; test_case <= T; test_case++) {
cin >> numberString >> trial_cnt;
memset(cache, -1, sizeof(cache));
int number = parse_int(numberString);
int answer = solve(parse_int(numberString), trial_cnt);
cout << '#' << test_case << ' ' << answer << '\n';
}
return 0;
}
int solve(int number, int cnt) {
if (cnt == 0)
return number;
if (cache[cnt][number] != -1)
return cache[cnt][number];
int length = length_of_int(number);
int &ret = cache[cnt][number];
int tmp = 0;
for (int i = 0; i < length; i++) {
for (int j = i + 1; j < length; j++) {
tmp = solve(swap_int(number, i, j), cnt - 1);
ret = (ret < tmp) ? tmp : ret;
}
}
return ret;
}
int swap_int(int number, int left_idx, int right_idx) {
int length = length_of_int(number);
int* tmp_arr = new int[length];
int digit = 0;
int ret = number;
for (int i = 0; i < length; i++) {
tmp_arr[i] = ret % 10;
ret /= 10;
}
if (tmp_arr[left_idx] == tmp_arr[right_idx]) {
delete[] tmp_arr;
return number;
}
digit = tmp_arr[left_idx];
tmp_arr[left_idx] = tmp_arr[right_idx];
tmp_arr[right_idx] = digit;
ret = 0;
for (int i = length - 1; i >= 0; i--)
ret = 10 * ret + tmp_arr[i];
return ret;
}
int parse_int(char* numberStr) {
int idx = 0;
int parsed = 0;
while (*(numberStr + idx) != '\0') {
parsed = parsed * 10 + *(numberStr + idx)-'0';
idx++;
}
return parsed;
}
int length_of_str(char* numberString) {
int idx = 0;
while(*(numberString + idx++) != '\0'){}
return idx - 1;
}
int length_of_int(int number) {
if (number == 0) return 1;
int cnt = 0;
while (number != 0) {
cnt++;
number /= 10;
}
return cnt;
}
Leave a comment