ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준 2580] - [백트래킹] - 스도쿠
    알고리즘/백트래킹 2018. 12. 21. 17:58

    문제링크 : https://www.acmicpc.net/problem/2580



    이문제는 백트래킹으로 접근 할 수 있는 문제이다.


    예전에 풀었던 N-Queen 문제도 백트래킹이었는데 간단하게 설명하자면 


    현재 인덱스에 값을 넣어보고 다음 탐색을 돌린다. 다시 현재 인덱스에는 값을 초기화 시킨다.


    arr[y][x] = i;

    backtracking(idx+1, cnt+1);

    arr[y][x] = 0;



    위에 소스처럼 백트래킹을 진행하는데 이렇게 하면 결국엔 다 초기화 되는거 아냐?? 하겠지만 잘 생각해보면 그렇지 않다.


    최종 arr의 값은 당연히 초기 탐색할때의 값이 되겠지만 탐색을 하는 도중에 맞는 결과가 나왔을거고 


    맞는 결과가 나왔을때 배열을 바로 출력을 했다. 


    이해가 안된다면 백트래킹에 대한 설명 N-Queen 문제를 풀어보고 이문제를 접근하면 접근법이 보일것이라 생각한다.


    2018/11/21 - [알고리즘/백트래킹] - [백준-9663]-[백트래킹] - N-Queen



    문제를 푸는 방법은 값을 입력 받을때 0을 입력받으면 좌표를 배열에 add 한다.


    배열에 add 한 좌표만 탐색하면 되기 때문에 list 에 add 한다.


    그다음 1 부터 9까지 입력 가능한 수를 해당 좌표에 대입 시키고 

    해당 좌표에 X 값이 위치했을때 성립하는지 같은 함수를 호출 해서 다음  탐색을 진행한다.


    그렇게 된다면 전부 입력되는 한 순간이 나오고 그 때 배열을 출력 시키고 결과가 출력 됐으니 더이상 진행 하지 말라고 isEnd 라는 플래그를 true로 변경하여


    더이상의 다른 불 필요한 탐색을 진행 못하게 막으면 된다.


    소스


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.StringTokenizer;
     
    public class Main {
        public static final int size = 9;
        public static int[][] arr;
        
        public static List<int[]> list;
        public static boolean isEnd;
        
        public static void main(String[] args) throws IOException{
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            
            StringTokenizer st = null;
            
            arr = new int[size][size];
            list = new ArrayList<>();
            
            for(int i=0; i < size; i++) {
                st = new StringTokenizer(br.readLine());
                
                for(int j=0; j < size; j++) {
                    arr[i][j] = Integer.parseInt(st.nextToken());
                    
                    if(arr[i][j] == 0) list.add(new int[] {i, j});
                }
            }
            // 입력 완료 
            backtracking(00);
            
        }
        public static void backtracking(int idx, int cnt) {
            // 결과가 나왔다면 조회할 필요가 없다.
            if(isEnd) return;
            
            //빈칸에 입력된 cnt가 초기 zero 값의 cnt와 같다면 전부 입력이 된것.
            if(cnt == list.size()) {
                isEnd = true;
                print();
                return;
            }
            // 인덱스가 list크기를 넘어가면 종
            if(idx >= list.size()) return;
            
            int y = list.get(idx)[0];
            int x = list.get(idx)[1];
            
            // 1 부터 9 까지 입력 가능한 숫자 를 확인한다.
            for(int i=1; i<=9; i++) {
                // 해당 숫자가 가능하면 해당 좌표에 값을 입력하고 backtracking을 한다. 
                if(isAble(y, x, i)) {
                    arr[y][x] = i;
                    backtracking(idx+1, cnt+1);
                    arr[y][x] = 0;
                }
            }
            
        }
        
        public static void print() {
            // 결과 출력
                    StringBuilder sb = new StringBuilder();
                    for(int i=0; i < size; i++) {
                        for(int j=0; j < size; j++) {
                            sb.append(arr[i][j] + " ");
                        }
                        sb.append("\n");
                    }
                    System.out.println(sb.toString());
        }
        public static boolean isAble(int y, int x, int v) {
            for(int i=0; i < size; i++) {
                // 가로가 유효한지 arr[y][x]의 값이 가로에 또 존재하면 안된다.
                if(arr[y][i] == v) return false;
                
                // 세로가 유효한지 arr[y][x]의 값이 세로에 또 존재하면 안된다.
                if(arr[i][x] == v) return false;
            }
            
            // 3*3이 유효한지
            int y_s = y/3 * 3;
            int x_s = x/3 * 3;
            for(int i = y_s; i < y_s+3; i++) {
                for(int j = x_s; j < x_s+3; j++) {
                    if(arr[i][j] == v) return false;
                }
            }
            return true;
        }
    }
    cs


    댓글

Designed by Tistory.