링크 : https://algospot.com/judge/problem/read/CLOCKSYNC
문제
그림과 같이 4 x 4 개의 격자 형태로 배치된 16개의 시계가 있다. 이 시계들은 모두 12시, 3시, 6시, 혹은 9시를 가리키고 있다. 이 시계들이 모두 12시를 가리키도록 바꾸고 싶다.
어떻게 풀까?
복잡해보이는 이 문제를 어떻게 풀 수 있을지 생각해봅시다.
우선, 스위치를 누를때 시계의 움직임이다. 시계는 스위치를 누르면, 3 - 6 - 9 - 12 - 3 ... 의 순서로 움직입니다.
즉, 스위치를 3번 이상 누르면 이전까지 누른 의미가 사라져 버린다는 것입니다!
이 사실을 깨닫고 나면,
10개의 스위치를
0번 누르는 경우,
1번 누르는 경우,
2번 누르는 경우,
3번 누르는 경우를 모두 탐색하는 '완전탐색' 기법을 사용하면 문제를 해결할 수 있을 것이라는 결론을 얻을 수 있습니다.
그렇다면 시간은 얼마나 걸릴까요?
스위치는 모두 10개이고, 스위치 마다 경우의 수가 4개 이므로, 4^10 = 2^20이 된다. 2^10을 1000 이라고 보면, 거의 1000000번의 계산을 한다고 생각하면 됩니다.
이는, 문제에서 주어진 시간 내에 풀릴 수 있을만한 범위입니다!
10중 for문을 이용해서 문제를 해결할 수 있지만, 재귀를 이용해서 계산해봤습니다. 코드는 아래와 같습니다!
코드
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 | #include<stdio.h> #include<string.h> int clocks[16]; int cntNum[10]; const int swNum[10] = { 3,4,4,5,5,4,3,5,5,5 }; const int swch[10][5] = { {0,1,2}, {3,7,9,11}, {4,10,14,15}, {0,4,5,6,7}, {6,7,8,10,12}, {0,2,14,15}, {3,14,15}, {4,5,7,14,15}, {1,2,3,4,5}, {3,4,5,9,13} }; int swCnt[10]; const int INF = 987654321; int min; int check() { int clockTemp[16]; memcpy(clockTemp, clocks, sizeof(clocks)); for (int i = 0; i < 10; i++) { for (int j = 0; j < swNum[i]; j++) { clockTemp[swch[i][j]]+= cntNum[i]; } } for (int i = 0; i < 16; i++) { if (clockTemp[i] % 4) return 0; } return 1; } int switchOn(int cnt,int now) { if (cnt >= min) return 0; if (now == 10) { if (check()) { min = min > cnt ? cnt : min; return 1; } return 0; } int res = 0; for (int i = 0; i < 4; i++) { cntNum[now] = i; res += switchOn(cnt + i, now + 1); } return res; } int CLOCKSYNC() { int c; scanf("%d\n", &c); while (c--) { memset(swCnt, 0, sizeof(swCnt)); min = INF; for (int i = 0; i < 16; i++) { scanf("%d \n", clocks + i); clocks[i] = (clocks[i] / 3) % 4; } if (switchOn(0,0)) { printf("%d\n", min); } else { printf("%d\n", -1); } } return 0; } | cs |
PLUS) 위의 코드는 900ms정도의 시간이 걸렸는데, 답을 보니 0ms의 시간이 걸린 코드가 있었습니다. 한번 이를 분석하겠습니다.
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 | #include <stdio.h> #include <limits.h> int switches[10][6] = { { 0,1,2,-1, }, { 3,7,9,11,-1, }, { 4,10,14,15,-1, }, { 0,4,5,6,7,-1, }, { 6,7,8,10,12,-1, }, { 0,2,14,15,-1, }, { 3,14,15,-1,}, { 4,5,7,14,15,-1, }, { 1,2,3,4,5,-1, }, { 3,4,5,9,13,-1, } }; int solve_clock_order[10] = {8,11,13,6,10,7,4,1,3,14}; int solve_switch_order[10] = {4,1,9,3,2,7,8,0,6,5}; int check_order[6] = {0,2,5,9,12,15}; int pairs[10] = {1,11,10,6,8,14,3,7,4,13}; int clocks[16]; int main() { int c; scanf("%d", &c); for (int i = 0; i < c; i++) { for (int j = 0; j < 16; j++) { int tmp; scanf("%d", &tmp); switch (tmp) { case 12: clocks[j] = 0; break; case 3: clocks[j] = 1; break; case 6: clocks[j] = 2; break; case 9: clocks[j] = 3; break; } } int total_cnt = 0; for(int j = 0; j < 10; j++) { int cnt = (4 - clocks[solve_clock_order[j]])%4; for(int k = 0; switches[solve_switch_order[j]][k] != -1; k++) { clocks[switches[solve_switch_order[j]][k]] = (clocks[switches[solve_switch_order[j]][k]] + cnt) % 4; } total_cnt += cnt; } bool possible = true; for(int j = 0; j < 6; j++) { if(clocks[check_order[j]] != 0) { possible = false; break; } } if(possible) { printf("%d\n", total_cnt); } else { printf("-1\n"); } } } | cs |
위의 코드에서 핵심은 3가지 입니다. 바로
이 부분입니다. 우선, 스위치를 확인해봅시다.
우선, 스위치 10개 중에서 딱 한번 등장하는 시계를 봅시다. 바로 4번 스위치의 8, 2번 스위치의 11, 5번 스위치의 13이다.
한 마디로, 8번 시계가 3시라면 4번 스위치를 3번 클릭하는 방법만이 8번 시계를 12시로 만들 수 있는 것입니다.
이런식으로 시계의 시간에 따라서 누를 수 밖에 없는 스위치들을 찾아 순서를 정하면, 위의 solve_siwtch_order 가 됩니다.
그 스위치와 연관되는 시계의 번호는 solve_clock_order가 됩니다.
스위치가 10개이고, 시계가 16개 이므로 모든 스위치를 눌러본 다음에 나머지 6개의 시계에 대해서는 답이 맞는지 확인을 해야합니다.
그 6개의 시계가 바로 check_order인 것입니다.
만약, 확인하는 시계들이 12시가 안된다면, 결국 저 스위치들을 눌러야하는데 그러면 결국 시계의 시간들이 다시 꼬여버리는 결과가 됩니다.
따라서, 10개의 스위치를 누른 다음에 나머지 6개의 시계가 12시를 가르키지 않는다면 결국 모든 시계를 12시로 만드는 방법이 없다는 것이고, -1을 출력하는 것입니다!
'공부 > 알고리즘 문제풀이' 카테고리의 다른 글
[알고스팟] 외발 뛰기 (0) | 2018.06.12 |
---|---|
[알고스팟] 팬 미팅 (0) | 2018.06.11 |
[알고스팟] 울타리 잘라내기 (0) | 2018.06.11 |
[알고스팟] 쿼드 트리 뒤집기 (0) | 2018.06.11 |
[SW Expert Academy] Code battle! (0) | 2018.06.06 |