Geisha 2025. 3. 3. 16:19

 

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

 

프로그래머스

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

programmers.co.kr

 

 

 

📌 자바(Java)로 푸는 기둥과 보 설치 문제 풀이 🚀


🔎 문제 개요

이 문제는 프로그래머스 - 기둥과 보 설치 문제입니다.
주어진 명령에 따라 기둥과 보를 설치하거나 삭제해야 합니다.
설치 조건을 만족하는 경우만 설치할 수 있으며, 삭제 후에도 구조물이 유지되는 경우만 삭제 가능합니다.


💡 예제 입력

int n = 5;
int[][] build_frame = {
    {1, 0, 0, 1},
    {1, 1, 1, 1},
    {2, 1, 0, 1},
    {2, 2, 1, 1},
    {5, 0, 0, 1},
    {5, 1, 0, 1},
    {4, 2, 1, 1},
    {3, 2, 1, 1}
};

💡 예제 출력

[[1,0,0],[1,1,1],[2,1,0],[2,2,1],[3,2,1],[4,2,1],[5,0,0],[5,1,0]]

🛠 알고리즘 접근 방식

이 문제를 해결하기 위해 구조물 유효성 검증 + 시뮬레이션을 활용합니다.

✏️ 주요 고려 사항

기둥과 보의 설치 조건을 만족해야만 설치 가능
삭제 후에도 전체 구조가 유지되는 경우만 삭제 가능
기둥과 보는 2차원 배열(pillars[][], beams[][])로 관리
삭제 가능 여부를 검증하는 canDelete() 함수 필요


🔹 Java 코드 해설

class Solution {

    boolean[][] pillars;  // 기둥 존재 여부
    boolean[][] beams;    // 보 존재 여부
    int count = 0;        // 설치된 구조물 개수

    public int[][] solution(int n, int[][] build_frame) {
        pillars = new boolean[n + 1][n + 1];
        beams = new boolean[n + 1][n + 1];

        for (int[] order : build_frame) {
            int x = order[0];
            int y = order[1];
            int type = order[2];  // 0: 기둥, 1: 보
            int action = order[3]; // 0: 삭제, 1: 설치

            if (type == 0) { // 기둥
                if (action == 1) {
                    if (isValidPillar(x, y)) {
                        pillars[x][y] = true;
                        count++;
                    }
                } else {
                    pillars[x][y] = false;
                    if (!canDelete(n)) pillars[x][y] = true;
                    else count--;
                }
            } else { // 보
                if (action == 1) {
                    if (isValidBeam(x, y)) {
                        beams[x][y] = true;
                        count++;
                    }
                } else {
                    beams[x][y] = false;
                    if (!canDelete(n)) beams[x][y] = true;
                    else count--;
                }
            }
        }

        int[][] answer = new int[count][3];
        int idx = 0;
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= n; j++) {
                if (pillars[i][j]) {
                    answer[idx][0] = i;
                    answer[idx][1] = j;
                    answer[idx++][2] = 0;
                }
                if (beams[i][j]) {
                    answer[idx][0] = i;
                    answer[idx][1] = j;
                    answer[idx++][2] = 1;
                }
            }
        }
        return answer;
    }

    // 삭제 가능 여부 확인
    public boolean canDelete(int n) {
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= n; j++) {
                if (beams[i][j] && !isValidBeam(i, j)) return false;
                if (pillars[i][j] && !isValidPillar(i, j)) return false;
            }
        }
        return true;
    }

    // 기둥 유효성 검증
    public boolean isValidPillar(int x, int y) {
        if (y == 0) return true; // 바닥 위
        else if (y > 0 && pillars[x][y - 1]) return true; // 아래에 기둥이 있음
        else if (x > 0 && beams[x - 1][y] || beams[x][y]) return true; // 보 위
        return false;
    }

    // 보 유효성 검증
    public boolean isValidBeam(int x, int y) {
        if (y > 0 && (pillars[x][y - 1] || pillars[x + 1][y - 1])) return true; // 한쪽 끝이 기둥 위
        else if (x > 0 && beams[x - 1][y] && beams[x + 1][y]) return true; // 양쪽 끝이 다른 보와 연결
        return false;
    }
}

🔍 코드 설명

📌 1. 구조물 설치 및 삭제 처리

for (int[] order : build_frame) {
    int x = order[0];
    int y = order[1];
    int type = order[2];  // 0: 기둥, 1: 보
    int action = order[3]; // 0: 삭제, 1: 설치
  • type == 0 → 기둥
  • type == 1 →
  • action == 1 → 설치
  • action == 0 → 삭제

📌 2. 기둥 설치 조건

if (y == 0) return true; // 바닥 위
else if (y > 0 && pillars[x][y - 1]) return true; // 아래에 기둥이 있음
else if (x > 0 && beams[x - 1][y] || beams[x][y]) return true; // 보 위
return false;

✔ 기둥은 바닥 위, 다른 기둥 위, 보의 끝 부분 위에 설치 가능


📌 3. 보 설치 조건

if (y > 0 && (pillars[x][y - 1] || pillars[x + 1][y - 1])) return true; // 한쪽 끝이 기둥 위
else if (x > 0 && beams[x - 1][y] && beams[x + 1][y]) return true; // 양쪽 끝이 다른 보와 연결
return false;

✔ 보는 한쪽 끝이 기둥 위, 혹은 양쪽 끝이 보와 연결되어야 설치 가능


📌 4. 삭제 가능 여부 확인

for (int i = 0; i <= n; i++) {
    for (int j = 0; j <= n; j++) {
        if (beams[i][j] && !isValidBeam(i, j)) return false;
        if (pillars[i][j] && !isValidPillar(i, j)) return false;
    }
}
return true;

✔ 삭제 후에도 모든 구조물이 유효한 경우에만 삭제 가능


🔥 시간 복잡도 분석


연산 최악의 경우 수행 횟수 시간 복잡도
for 루프 (설치/삭제 처리) n^2 O(n^2)
canDelete() (모든 구조물 검사) n^2 O(n^2)
총합   O(n^3)

최대 1000번 연산으로 제한 내 해결 가능


🏆 정리

핵심 포인트

설치 및 삭제 시 유효성 검증 필요
삭제 후에도 구조물이 유지되는지 확인 필요
O(n^3) 내에서 효율적으로 해결 가능


문제를 접했을 때 상당히 많은 글씨와 설명에 머리가 아팠고, 기둥과 보의 방향이 정해져있다는 것을 나중에서야 깨달아 방향처리를 어떻게해야할지 혼자 머리를 아프게 쥐싸맸던 문제입니다.  방향이 정해져 있기 때문에 boolean[][] 2차원 배열 2개로 위치를 파악할 수 있게 되더라구요.

문제를 어렵게 바라보는 습관을 고쳐야겠네요.. ㅎㅎ

 

이 글이 도움이 되셨다면 좋아요와 공유 부탁드립니다!