코딩테스트/코딩테스트(Java)

[코딩테스트] Java - 백트래킹

cogito30 2025. 3. 17. 19:35
반응형

백트래킹

- 완전탐색: dfs, bfs처럼 데이터를 전부 확인하는 방법

- 백트래킹(backtracking): 가능성이 없는 곳에서는 되돌아가고, 가능성이 있는 곳을 탐색하는 알고리즘

- 유망함수(promising function): 특정 조건을 정하는 함수

 

(백트래킹 풀이법)

1. 유효한 해의 집합을 정의

2. 정의한 집합을 그래프로 표현

3. 유망함수 정의

4. 백트래킹을 통한 해 탐색

 

(부분 집합 합)

- 부분 집합 합(sum of subset): 1부터 N까지 숫자르 조합했을 때 합이 K가 되는 조합을 찾는 문제

- 유망함수1: 현재 조합으로 합이 K일 경우 탐색 중지

- 유망함수2: 해당 숫자를 조합하여 합이 K 이상이 되면 탐색 중지

 

(N-Queen)

- N-Queen: 체스의 퀸을 N x N 체스판에 N개 배치시 서로 공격할 수 없는 위치에 놓을 수 있는 방법의 수를 찾는 문제. 퀸은 상하좌우대각으로 이동 가능

- 유망함수: 퀸 추가시 동일 행이나 열, 대각선 방향에 중복된 퀸 존재시 탐색 중지

 

예제

(1부터 N까지 숫자 중 합이 K가 되는 조합)

- 유망함수1: 조합한 숫자의 합이 K일 경우 리스트에 추가

- 유망함수2: 조합한 숫자의 합이 10보다 크면 백트래킹

- 입력: N, K

- 출력: 합이 K가 되는 숫자들의 리스트(2차원 배열)

더보기
import java.util.ArrayList;

class Solution {
    private static ArrayList<ArrayList<Integer>> result;
    private static int n;
    private static void backtrack(int sum, ArrayList<Integer> selectedNums, int start) {
        if (sum == 10) {
            result.add(selectedNums);
            return;
        }
        
        for (int i = start; i <= n; ++i) {
            if (sum + i <= 10) {
                ArrayList<Integer> list = new ArrayList<>(selectedNums);
                list.add(i);
                backtrack(sum + i, list, i + 1);
            }
        }
    }
    
    private static ArrayList<ArrayList<Integer>> solution(int N) {
        result = new ArrayList<>();
        n = N;
        
        backtrack(0, new ArrayList<>(), 1);
        return result;
    }
}

 

(스도쿠 퍼즐)

- 스도쿠 퍼즐: 9 x 9 스도쿠 보드를 다 채원 완성된 스도쿠 보드를 반환

- 스도쿠 퍼즐 조건1: 가로줄, 세로줄에는 1부터 9까지의 숫자가 한 번씩 나타나야 함

- 스도쿠 퍼즐 조건2: 9 x 9 보드를 채울 9개의 작은 박스(3 x 3 크기)에도 1부터 9까지의 숫자가 한 번씩 나타나야 함

- 유망함수1: 해당 행에 넣으려는 숫자가 있는지 확인

- 유망함수2: 해당 열에 넣으려는 숫자가 있는지 확인

- 유망함수3:  해당 위치를 포함하는 3 x 3 박스에 넣으려는 숫자가 있는지 확인

 

- 입력: board(2차원 행렬의 스도쿠 퍼즐)

- 출력: 2차원 행렬

더보기
import java.util.Arrays;

class Solution {
    private static class Block {
        int i, j;
        public Block(int i, int j) {
            this.i = i;
            this.j = j;
        }
    }
    
    private static int[][] Board;
    
    private static boolean isValid(int num, int row, int col) {
        return !(inRow(num, row) || inCol(num, col) || inBox(num, row, col));
    }
    
    private static boolean inRow(int num, int row) {
        return Arrays.stream(Board[row]).anyMatch(n -> n == num);
    }
    
    private static boolean inCol(int num, int col) {
        for (int i = 0; i < 9; i++) {
            if (Board[i][col] == num) return true;
        }
        return false;
    }
    
    private static boolean inBox(int num, int row, int col) {
        int boxRow = (row / 3) * 3;
        int boxCol = (col / 3) * 3;
        
        for (int i = boxRow; i < boxRow + 3; ++i) {
            for (int j = boxCol; j < boxCol + 3; ++j) {
                if (Board[i][j] == num) {
                    return true;
                }
            }
        }
        return false;
    }
    
    private static Block findEmptyPosition() {
        for (int i = 0; i < 9; ++i) {
            for (int j = 0; j < 9; ++j) {
                if (Board[i][j] == 0) {
                    return new Block(i, j);
                }
            }
        }
        return null;
    }
    
    private static boolean findSolution() {
        Block emptyPos = findEmptyPosition();
        if (emptyPos == null)
            return true;
            
        int row = emptyPos.i;
        int col = emptyPos.j;
        
        for (int num = 1; num <= 9; num++) {
            if (isValid(num, row, col)) {
                Board[row][col] = num;
                if (findSolution()) {
                    return true;
                }
                Board[row][col] = 0;
            }
        }
        return false;
    }
    
    private static int[][] solution(int[][] board) {
        Board = board;
        findSolution();
        return board;
    }

}

 

반응형