복기
숫자도 적고 딱봐도 시뮬레이션인 문제입니다. 딱! 보고 게임판에 숫자를 어떻게 저장할지 막막하기도 했고요. 특별한 방법은 생각나지 않았지만 파란색칸이 공통적으로 다섯 번에 한 번씩 있어서 '5로 나눠 떨어질 때 길을 바꿔주면 좋겠다.', '게임판을 이차원 배열에 저장하고 각 길을 하나의 행으로 표현하면 5로 나눈 몫을 보고 길을 바꿔줄 수 있겠다' 정도만 생각하고 맵을 이차원 배열로 선언했습니다....만 언제든지 지울 수 있는 상태였죠.
1 2 3 4 5 6 | int map[5][35] = { { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 0, }, { 10, 13, 16, 19, 25, 30, 35, 40, 0, }, { 0, 20, 22, 24, 25, 30, 35, 40, 0, }, { 30, 28, 27, 26, 25, 30, 35, 40, 0, }, }; | cs |
2번째 길(20, 22, ...)만 다른 길과 길이가 달라서 중복체크를 쉽게하려고 앞에 0을 넣어 길이를 맞췄구요.
4개 말을 무작위로 10회 움직이는 경우는 4^10 = 1M 번이니까 완전 탐색을 해도 시간은 충분합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | void play(int lvl, int sum) { if (lvl >= 10) { if (ans < sum) ans = sum; return; } for (int n = 0; n < 4; n++) { // 갈 수 있는지? // 없으면, continue; // 있으면, get 갔을 때 얻는 점수 play(lvl + 1, sum + score); } } int main(void) { for (int i = 0; i < 10; i++) scanf("%d", &dice[i]); play(0, 0); printf("%d\n", ans); return 0; } | cs |
먼저, 큰 틀로 전체 탐색하는 코드만 작성해놨고 '갈 수 있는지 확인하는 부분만 따로 함수를 만들어봐야지' 했습니다. 몇 번째 플레이어가 갈 차례인지, 얼마나 갈건지를 입력으로 하고 갈 수 없으면 마이너스 값 반환, 갈 수 있으면 더할 점수를 반환하는 함수를 만들기로 했고요. 대강 윤곽만 잡아보니
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | int go(int n, int dis) { // 이미 도착한 플레이어? 이동 불가 return -1; // 현재 파란원? 길 바꾼다 // 이동 // 도착 ? return 0; // 이미 누가 있다면? 이동 불가 return -1; // 점수 반환 return map[player[n].x][player[n].y]; } | cs |
이었고 이정도 쓰고 나선 막연하게 이거 되겠다하는 생각이 들었습니다.
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | #pragma warning(disable : 4996) #include <stdio.h> struct Player { int x, y; }; struct Player player[5]; int dice[15], ans; int map[5][35] = { { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 0, }, { 10, 13, 16, 19, 25, 30, 35, 40, 0, }, { 0, 20, 22, 24, 25, 30, 35, 40, 0, }, { 30, 28, 27, 26, 25, 30, 35, 40, 0, }, }; int go(int n, int dis) { struct Player npc = player[n]; int end = 21; // blue point ? change road if (npc.x == 0 && npc.y < end) { int q = npc.y / 5; int r = npc.y % 5; if (q < 4 && r == 0) { npc.x = q; npc.y = q == 2; } } if (npc.x != 0) end = 8; // already end ? can't pick it up if (npc.y >= end) return -1; // move npc.y += dis; // end ? return 0 if (npc.y >= end) { player[n] = npc; return 0; } // has owner ? can't pick it up for (int i = 0; i < 4; i++) { if (i == n) continue; if (npc.x == player[i].x) { if (npc.y == player[i].y) return -1; } else if (npc.x > 0 && player[i].x > 0) { if (npc.y == player[i].y && npc.y >= 4) return -1; } else { int n1 = map[npc.x][npc.y]; int n2 = map[player[i].x][player[i].y]; if (n1 == n2 && n1 == 40) return -1; } } // moving alright ? move player[n] = npc; return map[npc.x][npc.y]; } void play(int lvl, int sum) { struct Player save; int dis; if (lvl >= 10) { if (ans < sum) ans = sum; return; } for (int n = 0; n < 4; n++) { save = player[n]; dis = go(n, dice[lvl]); if (dis < 0) continue; play(lvl + 1, sum + dis); player[n] = save; } } int main(void) { for (int i = 0; i < 10; i++) scanf("%d", &dice[i]); player[0].y = dice[0]; play(1, map[0][dice[0]]); printf("%d\n", ans); return 0; } | cs |
반성할 점으로는 play() 함수에서 go() 함수를 들어가기 전과 후로 전역 변수 player가 달라지기 때문에 당연히 저장해두었다가 나왔을 때 복구해야하는데 이 부분을 생각하지 못하고 '왜 틀리지?' 하며 go() 함수 안만 들여다보느라 시간을 허비한 점이 있습니다. 항상 함수를 작성할 때는 입력과 출력이 무엇인지? 어떤 처리를 하는 함수인지? 함수 수행으로 변화되는 것이 무엇인지? 어떻게 사용할 것인지? 등을 객관적으로 생각해야하는데 함수 내부 구현에 집중하다보면 계속 놓치게 되는 것 같습니다. ㅜ_ㅜ;
보고나서 좋다고 생각했던 코드로는 아이디 goooora 님의 코드가 있습니다. (https://www.acmicpc.net/source/16404426)
코드를 보면 코드양도 적고 되게 직관적이라 코드 작성 시간이 굉장히 짧았을 것으로 추측됩니다. 복기끝.
'개발 > c' 카테고리의 다른 글
[백준] 15683 감시 (0) | 2020.05.09 |
---|---|
[백준] 16236 아기 상어 (0) | 2020.04.28 |
[백준] 17822 원판 돌리기 (0) | 2020.04.22 |
[백준] 3111 검열 (0) | 2019.03.05 |
[백준] 4179 불! (0) | 2018.12.13 |