본문 바로가기
Problem Solving/Baekjoon

[백준] 15684 사다리 조작 - Backtracking / Java

by graycode 2022. 9. 19.

 문제 링크

 

15684번: 사다리 조작

사다리 게임은 N개의 세로선과 M개의 가로선으로 이루어져 있다. 인접한 세로선 사이에는 가로선을 놓을 수 있는데, 각각의 세로선마다 가로선을 놓을 수 있는 위치의 개수는 H이고, 모든 세로선

www.acmicpc.net

 

 풀이 과정

n개의 세로선에 h개의 점선이 가로로 교차되어 있는 사다리에 m개의 가로선의 정보를 입력받는다.

2차원 boolean 배열에 입력받은 좌표 기준 오른쪽 방향에 가로선이 있을 시 true 로 저장한다.

 

가로선은 없거나 최대 3개까지 사용 가능하므로 가로선이 0 ~ 3개 추가로 설치한 경우를 모두 확인한다.

 

재귀 함수(recur) 의 2중 for문에서 현재 위치 기준 오른쪽 방향으로 가로선이 존재하지 않을 경우 (!map[i][j])

백트래킹을 통하여 특정 층에서 가로선을 설치하는 모든 경우의 수를 확인한다.

 

재귀를 통해 증가된 가로선의 개수(cnt) 가 현재 목표 가로선(min = i) 의 개수와 일치하다면

현재 사다리를 통해 모든 i번 세로선 경로의 결과가 i인지 확인한다.(isPass)

 

각 층의 현재 위치에서 오른쪽(map[y][x]), 왼쪽(map[y][x - 1]) 으로 이동 가능한 가로선이 있는 지 확인하며

존재하는 가로선 경로로 한층씩 내려간다.(y++)

만약 각각의 i번 세로선 경로의 결과가 i 일 경우 true 를 반환, 아닌 경우 false 를 반환한다.

 

이렇게 최소 가로선의 개수가 구해진다면 해당 값을, 구하지 못하였다면 -1 을 정답으로써 출력한다.

 

 풀이 코드

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main {

    static int n, m, h;
    static boolean[][] map;
    static boolean finish;
    static int min = Integer.MAX_VALUE;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        h = Integer.parseInt(st.nextToken());

        map = new boolean[h + 1][n + 1];

        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            int y = Integer.parseInt(st.nextToken());
            int x = Integer.parseInt(st.nextToken());
            map[y][x] = true;
        }

        for (int i = 0; i <= 3; i++) {
            min = i;
            recur(1, 0);

            if (finish)
                break;
        }

        bw.write((finish ? min : -1) + "\n");
        bw.flush();
    }

    private static void recur(int idx, int cnt) {
        if (finish)
            return;

        if (min == cnt) {
            if (isPass())
                finish = true;

            return;
        }

        for (int i = idx; i <= h; i++) {
            for (int j = 1; j < n; j++) {
                if (!map[i][j]) {
                    map[i][j] = true;
                    recur(i, cnt + 1);
                    map[i][j] = false;
                }
            }
        }
    }

    private static boolean isPass() {
        for (int i = 1; i <= n; i++) {
            int y = 1;
            int x = i;

            for (int j = 0; j < h; j++) {
                if (map[y][x])
                    x++;
                else if (map[y][x - 1])
                    x--;

                y++;
            }

            if (x != i)
                return false;
        }

        return true;
    }

}

댓글