반응형
문제
4X4 의 격자 형태로 배치된 16개의 시계가 있습니다. 이 시계들은 모두 12시 3시,6시,9시 를 가리키고 있는데, 이 시계들이 모두 12시를 가리키도록 바꾸고 싶습니다. 10개의 스위치를 조작해 이 시계를 3시간 앞으로 당길 수 있는데, 이 스위치들은 아래 표와 같이 연결되어있습니다.
스위치 번호 | 연결된 시계 | 스위치 번호 | 연결된 시계 |
0 | 0, 1, 2 | 5 | 0, 2, 14, 15 |
1 | 3, 7, 9, 11 | 6 | 3, 14, 15 |
2 | 4, 10, 14, 15 | 7 | 4, 5, 7, 14, 15 |
3 | 0, 4, 5, 6, 7 | 8 | 1, 2, 3, 4, 5 |
4 | 6, 7, 8, 10, 12 | 9 | 3, 4, 5, 9, 13 |
- 입력
- 테스트 케이스 C (C<=30)
- 16개의 정수 (12,3,6,9) = 0~15번까지 시계가 지금 가리키고 있는 시간
- 출력
- 각 테스트 케이스당 스위치를 누를 최소 횟수. (실패하면 -1)
문제 링크 : https://www.algospot.com/judge/problem/read/CLOCKSYNC
풀이
- 10개의 스위치에 따라 16개의 시계가 작동됨을 나타낸 switchList[10] [16] 작성.
- c가 입력되면, c만큼 함수 solve() 진행
- solve()에서는 16개의 시계의 시간을 (clock[])에 넣고 최소 횟수를 찾는 switchClock() 실행.
- switchClock()은 배열 clock[]과 몇번째 스위치를 누를 것인지 정하는 switchnum을 인자로 받음
탈출 조건으로 switchnum == switchList.length( = 10) 일때 (스위치 10번째 누르는 것까지 모든 경우의 수를 다했을때) 모든 시계가 12시이면 (isclock12) 0을, 아니면 9999를 return. - count = 9999 (성공 못할때) 로 설정해놓고, for문 실행
스위치를 누르는 순서와는 관계없이, 몇번 누르냐에 따라서 문제 해결 가능
이때 스위치를 4번 누르면 한바퀴가 돌아 다시 원점으로 돌아옴.
따라서 10가지 스위치를 0~3번씩 모두 눌러보는 경우만 생각하면 됨.
1. 기존의 count와 이번에 버튼 누른 횟수 + switchnum+1으로 다시 돌린 switchClock에서 최솟값을 비교
2. 버튼 누르기 (0~3) // 이때 결국 버튼은 0 1 2 3 4번 눌렸으니 원래의 값으로 되돌아감.(재귀 호출 후 초기화) - 버튼 누르는 함수는 switchList[] [] 에서 switchnum 행에서 1인 애 찾아서 그 값에 해당하는 clock[]에 3 더하기.
- 만약 최종값이 9999 이상이면 (완전탐색 이후에도 해결되지 않았다면) 문제의 조건에 따라 -1로 바꿔주고 출력
코드 (JAVA)
import java.util.ArrayList;
public class CLOCKSYNC {
public static StringBuilder sb = new StringBuilder();
public static java.util.Scanner sc = new java.util.Scanner(System.in);
public static int C;
public static int[] clock = new int[16];
public static int ans;
public static int[][] switchlist = {{1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0},{0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,1},
{1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,1,1,1,0,1,0,1,0,0,0},
{1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1},{0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1},
{0,0,0,0,1,1,0,1,0,0,0,0,0,0,1,1},{0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,1,1,0,0,0,1,0,0,0,1,0,0}};
public static void main(String[] args)throws Exception {
C = sc.nextInt();
sc.nextLine();
for(int i=0;i<C;i++) {
solve();
}
System.out.println(sb.toString());
}
static void solve() throws Exception {
//시계 상태 넣기.
for(int i = 0; i < clock.length; i++) {
clock[i] = sc.nextInt();
}
ans = switchClock(clock,0);
if(ans >= 9999){
ans = -1;
}
sb.append(ans).append("\n");
ans = 0;
}
//12시인지 체크
static boolean isclock12(int[] clock) {
for(int i=0; i<clock.length; i++) {
if(clock[i] != 12)
return false;
}
return true;
}
//버튼 누르는 애
static void click(int switchnum, int[] clock) {
for(int j = 0; j < switchlist[switchnum].length; j++) {
if(switchlist[switchnum][j] == 1) {
clock[j] = clock[j] + 3;
}
if(clock[j] == 15) clock[j] = 3;
}
}
static int switchClock(int clock[], int switchnum) throws Exception {
//다 눌렀을 때
if(switchnum == switchlist.length) {
return isclock12(clock) ? 0 : 9999;
}
int count = 9999;
//3일때 한번 더 눌러서 원상태 만들고 다음 재귀함수 돌릴 수있음.
for(int i =0; i<4; i++) {
count = Math.min(count,i+switchClock(clock,switchnum+1));
click(switchnum,clock);
}
return count;
}
}
복기
처음에 시계 기준으로 생각함.
눌러야 하는 시계 모두 찾기 -> 그 시계들과 최대한 많이 겹치는 버튼 누르기 -> 이걸 계속 진행
이렇게 생각했으나, 너무 어려워서 실패.
두번째는 시계 누르는 순서는 상관 없음을 생각하고
눌러야 하는 시계들을 계속해서 탐색해 0번부터 눌러보려고생각 -> stackoverflow 에러로 실패.
책을 보고( 0 1 2 3 ) 4가지 경우의 수 만 가능하고, for문을 0~3까지 돌리면 초기화 됨을 알아내고 함.
재귀함수를 돌릴때 반환형을 int로 할지 ,void로 할지 여전히 헷갈림
주로 가능한 경우의 수는 void, 최적의 값이나 경로는 int로 하는 것 같음.
2020.02.15
반응형
'알고리즘 > 문제풀이' 카테고리의 다른 글
책 페이지 (백준 1019번) (0) | 2020.07.09 |
---|---|
쿼드 트리 (백준 1992번) (0) | 2020.07.07 |
알약 (백준 4811번) (0) | 2020.07.07 |
게임판 덮기 [알고스팟] (ID : BOARDCOVER) (0) | 2020.07.07 |
소풍 [알고스팟] (ID : PICNIC) (0) | 2020.07.07 |
Comment