[JS] 고고학 최고의 발견
FrontEnd/프로그래머스

[JS] 고고학 최고의 발견

728x90

문제만 놓고 보면 완전탐색 문제같아 보인다.

 

실제로 모든 케이스를 검사한다고 생각한다면...

 

들어올수 있는칸이 64칸이므로 4 ^ 64 즉 절대로 시간안에 풀 수 없는 경우의 수가 나온다.

 

 

문제를 약간 생각해본다면 위 경우의 수를 획기적으로 줄일 수 있다.

 

만약에 퍼즐의 맨 윗칸이 고정되어 있다고 생각해보자. 

 

01030213 <== 이런식으로 맨 윗줄을 고정해둔다고 생각해두면, 해당 줄을 00000000으로 만들기 위해서는 반드시 그 아래의 시계를 돌려야 한다.

 

시계가 십자모양이므로 한줄이 고정된다면 그 줄을 바꾸기 위해서는 해당 시계의 아래에 있는 시계로만 동작이 가능하기 때문이다.

 

 

 

 

위 경우에서 맨 윗줄이 ↑←←↑ 로 고정되어 있다고 생각해보자.

 

두번째 ← 를 바꾸기 위해서는 노란색으로 색칠되어 있는 ↓ 말고는 제어할 수가 없다.

 

 

같은 방식으로 첫줄,두번째줄... 진행한다면 첫줄에 의해서 나머지 줄들이 정해지게 된다.

 

 

따라서 모든 경우의수를 따지는 것이 아닌 첫 줄의 경우의 수만 줄이면 되므로

 

4 ^ 8 의 경우의 수만 따져주면 된다.

 

 

필자가 문제를 푼 방법은 아래와 같다.

 

1. 지도에서 시계까 회전하는 함수를 구현

2. 첫줄이 고정되었다고 가정하고 시계를 돌렸을때 해결할 수 있는지 유무를 확인하는 함수를 구현

 -> 해결할 수 없다면 false 반환

 -> 해결할 수 있다면 돌린 횟수를 반환

 

3. 첫줄을 dfs를 활용해서 4가지 케이스씩 4^n의 케이스를 돌려가면서 확인

4. 나온 값들 중 가장 작은 값을 반환

 

 

 

function solution(clockHands) {
    const len = clockHands.length
    const dc = [0,1,0,-1,0]
    const dr = [0,0,1,0,-1]
    
    const change = (r,c,map) => {
        for (let k = 0 ; k < 5 ; k++){
            const [nr,nc] = [r + dr[k] , c + dc[k]]
            if (0<= nr && nr<len && 0<= nc && nc < len){
                map[nr][nc] = (map[nr][nc] + 1) % 4
            }
        }
    }
    
    const checkMap = (map) => {
        const tmpMap = map.map(v => [...v])
        let ret = 0
        for (let i = 1 ; i < len ; i ++){
            for (let j = 0 ; j < len ; j++){
                const maxK = (4 - tmpMap[i-1][j])%4
                for (let k = 0 ; k < maxK ; k++){
                    change(i,j,tmpMap)
                    ret ++
                }
            }
        }
        
        for (let i = 0 ; i < len ; i++){
            for (let j = 0 ; j < len ; j++){
                if(tmpMap[i][j]) return false
            }
        } 
        return ret
    }
    
    const retAry = []
    const dfs = (n,cnt) =>{
        if (n===len) {
            const ret = checkMap(clockHands)
            
            if (ret!==false) retAry.push(ret + cnt) 
            return
        }
        
        for (let i = 0 ; i <4 ; i++){
            dfs(n+1,cnt+i)
            change(0,n,clockHands)
        }
    }
    dfs(0,0)
    return Math.min(...retAry)
}
728x90

'FrontEnd > 프로그래머스' 카테고리의 다른 글

[JS] 등산코스 정하기  (2) 2023.10.28
[JS] 카운트 다운  (0) 2023.10.24
[JS] 2차원 동전 뒤집기  (0) 2023.10.23
[JS] 부대복귀  (1) 2023.10.21
[JS,Python] 등대  (1) 2023.10.20