개발/알고리즘

[프로그래머스] 기둥과 보 설치

이프로🍑 2025. 4. 25. 21:47

 

 

https://school.programmers.co.kr/learn/courses/30/lessons/60061

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

문제 요약

  • 기둥과 보를 2차원 공간에 설치하거나 제거한다.
  • 설치 및 삭제는 각각의 조건을 만족해야 한다.
  • 최종적으로 남은 구조물들을 (x, y, 구조물 타입) 형식으로 정렬해 반환해야 한다.

구조물 상태 표현 방식: 비트마스킹

각 좌표에서 구조물의 상태 관리하기 위해 int[][] map 배열을 사용했다.
각 구조물의 위치 상태는 비트마스크를 활용하여 다음과 같이 정의한다.

static final int PILLAR_START = 1; // 기둥 아래
static final int PILLAR_END   = 2; // 기둥 위
static final int BEAM_START   = 4; // 보 왼쪽
static final int BEAM_END     = 8; // 보 오른쪽

예를 들어, map[x][y]의 값이 PILLAR_START + BEAM_START이면 (x, y) 위치에 기둥과 보가 동시에 설치되어 있음을 의미한다.


설치 조건 함수

구조물마다 설치 조건이 다르므로 이를 각각 별도의 함수로 분리하여 정의한다.

private boolean checkPillar(int x, int y) {
    if (y == 0) return true;
    return (map[x][y] & (BEAM_START + BEAM_END + PILLAR_END)) != 0;
}

private boolean checkBeam(int x, int y) {
    if ((map[x][y] & PILLAR_END) != 0 || (map[x + 1][y] & PILLAR_END) != 0) return true;
    return (map[x][y] & BEAM_END) != 0 && (map[x + 1][y] & BEAM_START) != 0;
}

삭제 조건 검증 및 롤백 처리

삭제 시 중요한 점은, 삭제로 인해 연결된 구조물이 설치 조건을 위반하는지 확인해야 한다는 점이다.
이를 위해 연결된 구조물만 선별적으로 확인하고, 조건을 위반할 경우 삭제를 롤백한다.

boolean rollback = false;

// 기둥 삭제
map[x][y + 1] -= PILLAR_END;

if ((map[x][y + 1] & BEAM_END) != 0 && !checkBeam(x - 1, y + 1)) rollback = true;
else if ((map[x][y + 1] & BEAM_START) != 0 && !checkBeam(x, y + 1)) rollback = true;
else if ((map[x][y + 1] & PILLAR_START) != 0 && !checkPillar(x, y + 1)) rollback = true;

if (rollback) {
    map[x][y + 1] += PILLAR_END;
} else {
    map[x][y] -= PILLAR_START;
}

보 삭제 또한 동일한 원리로 처리된다.


최종 결과 반환

설치가 끝난 후, 모든 좌표를 순회하며 남아 있는 구조물을 정리한다.
문제 조건에 따라 (x → y → 구조물 타입) 순으로 자동 정렬이 되도록 이중 for문을 활용했다.

ArrayList<int[]> result = new ArrayList<>();

for (int x = 0; x <= N; x++) {
    for (int y = 0; y <= N; y++) {
        if ((map[x][y] & PILLAR_START) > 0) result.add(new int[]{x, y, 0});
        if ((map[x][y] & BEAM_START) != 0) result.add(new int[]{x, y, 1});
    }
}

return result.toArray(new int[result.size()][]);

 


전체 코드

import java.util.*;

class Solution {
    static final int PILLAR_START = 1;
    static final int PILLAR_END = 2;
    static final int BEAM_START = 4;
    static final int BEAM_END = 8;
    
    static int[][] map;
    static int N;
    
    public int[][] solution(int n, int[][] build_frame) {
        this.N = n;
        
        map = new int[N+2][N+2];
        
        for(int[] frame : build_frame) {
            int x = frame[0];
            int y = frame[1];
            int a = frame[2];
            int b = frame[3];
        
            //설치
            if(b == 1) {
                if(a == 0 && checkPillar(x, y)) {
                    map[x][y] |= PILLAR_START;
                    map[x][y+1] |= PILLAR_END;
                }
                else if(a == 1 && checkBeam(x, y)) {
                    map[x][y] |= BEAM_START;
                    map[x+1][y] |= BEAM_END;
                }
                
                continue;
            }
            
            //삭제
            boolean rollback = false;
            
            //기둥 삭제
            if(a == 0) {
                
                map[x][y+1] -= PILLAR_END; 
                
                if((map[x][y+1] & BEAM_END) != 0 && !checkBeam(x-1, y+1)) {
                    rollback = true;
                }
                else if((map[x][y+1] & BEAM_START) != 0 && !checkBeam(x, y+1)) {
                    rollback = true;
                }
                else if((map[x][y+1] & PILLAR_START) != 0 && !checkPillar(x, y+1)) {
                    rollback = true;
                }
                
                if(rollback)
                    map[x][y+1] += PILLAR_END;
                else
                    map[x][y] -= PILLAR_START;
                
                continue;
            }
            
            //보 삭제
            map[x][y] -= BEAM_START;
            map[x+1][y] -= BEAM_END;
            
            if((map[x][y] & BEAM_END) != 0 && !checkBeam(x-1, y)) {
                rollback = true;
            }
            else if((map[x][y] & PILLAR_START) != 0 && !checkPillar(x, y)) {
                rollback = true;
            }
            else if((map[x+1][y] & BEAM_START) != 0 && !checkBeam(x+1, y)) {
                rollback = true;
            }
            else if((map[x+1][y] & PILLAR_START) != 0 && !checkPillar(x+1, y)) {
                rollback = true;
            }
            
            if(rollback) {
                map[x][y] += BEAM_START;
                map[x+1][y] += BEAM_END;
            }
            
        }
        
        ArrayList<int[]> result = new ArrayList<>();
        
        for(int x=0; x<=N; x++) {
            for(int y=0; y<=N; y++) {
                if((map[x][y] & PILLAR_START) > 0)
                    result.add(new int[] {x, y, 0});
                
                if((map[x][y] & BEAM_START) != 0)
                    result.add(new int[] {x, y, 1});
            }
        }
        System.out.println(result.size());
        return result.toArray(new int[result.size()][]);
    }
    
    private boolean checkPillar(int x, int y) {
        //1. 바닥 위에 있거나.
        if(y==0) {
            return true;
        }
        //2. 보의 한쪽 끝 부분 위에 있거나.
        //3. 다른 기둥 위에 있거나.
        else if((map[x][y] & (BEAM_START + BEAM_END + PILLAR_END )) != 0) {
            return true;
        }
        
        return false;
    }
    
    private boolean checkBeam(int x, int y) {
        //1. 한쪽 끝 부분이 기둥 위에 있거나.
        if((map[x][y] & PILLAR_END) != 0 || (map[x+1][y] & PILLAR_END) != 0) {
            return true;
        }
        //2. 양쪽 끝 부분이 다른 보와 동시에 연결되어 있거나.
        else if((map[x][y] & BEAM_END) != 0  && (map[x+1][y] & BEAM_START) != 0) {
            return true;
        }
        
        return false;
    }
}