CodingTest

백 준 - 2580

electronicprogrammer 2020. 11. 2. 04:42

문제 : www.acmicpc.net/problem/2580

 

2580번: 스도쿠

스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루

www.acmicpc.net

문제는 다음과 같습니다.

 

문제의 핵심은 스도쿠에서 몇 칸이 0으로 변경된 입력이 주어지면 해당 입력을 적절한 값으로 채워서 스도쿠를 완성하는 것입니다.

여기서 스도쿠가 만들어질 수 있는 경우만 입력이 되므로 저희는 백트랙킹 즉 모든 경우를 하나하나 검사하면서 경우를 충족하지 못하면 해당 경우를 삭제하도록 하는 방법을 생각해볼 수 있습니다.

 

경우를 삭제하는 것은 스도쿠의 규칙 , 열, 행 그리고 주위 구역에서의 1,2,3,4,5,6,7,8,9 에서 중복된 수가 있는가? 입니다.

 

해서 주어진 제한조건에 어긋나지 않다면 해당 칸에 값을 채우고 다음 칸으로 이동하는 식으로 제귀를 구현할 수 있습니다. 과정을 정리하면 다음과 같습니다. 

 

전체적인 코드는 다음과 같습니다.

import java.util.*;

public class Main {

    //문제 2580

    public static boolean first = false;

    public static int[][] ans = new int[9][9];

    public static void main(String[] args) {

        Scanner stdin = new Scanner(System.in);

        int[][] arr = new int[9][9];

        for (int i = 0 ; i < 9 ; i++) {

            for(int j = 0 ; j < 9 ; j++) {

                arr[i][j] = stdin.nextInt();
            }
        }

        recursive(arr , 0 , 0);

        for(int i = 0 ; i < ans.length ; i++) {

            for(int j = 0 ; j < ans.length ; j++) {

                System.out.print(ans[i][j] + " ");
            }

            System.out.println();
        }

    }

    public static void recursive(int[][] arr , int x , int y) {

        if( x == 0 && y == arr.length) {

            if (first == false) {

                for(int i = 0 ; i < ans.length ; i++) {

                    for(int j = 0 ; j < ans.length ; j++) {

                        ans[i][j] = arr[i][j];
                    }
                }

                first = true;
            }

            return;
        }

        if (arr[y][x] == 0) {

            for (int i = 1; i < 10 ; i++) {

                arr[y][x] = i;

                if ((check1(arr , x)) && check2(arr, y) && check3(arr , x , y)) {

                    if (x == arr.length-1) {

                        recursive(arr , 0 , y+1);
                    }
                    else {

                        recursive(arr , x+1 , y);
                    }
                }

                arr[y][x] = 0;
            }
        }
        else {

            if (x == arr.length-1) {

                recursive(arr , 0 , y+1);
            }
            else {

                recursive(arr , x+1 , y);
            }

        }

    }

    public static boolean check1(int[][] arr , int x) {

        boolean[] flag = new boolean[10];

        for (int i = 0 ; i < arr.length ; i++) {

            int num = arr[i][x];

            if (flag[num] == false) {

                flag[num] = true;
            }
            else {
                if (num != 0)
                    return false;
            }
        }

        return true;
    }

    public static boolean check2(int[][] arr , int y) {

        boolean[] flag = new boolean[10];

        for (int i = 0 ; i < arr.length ; i++) {

            int num = arr[y][i];

            if (flag[num] == false)
                flag[num] = true;
            else{
                if (num != 0)
                    return false;
            }
        }

        return true;

    }

    public static boolean check3(int[][] arr , int x , int y) {

        int ptrX = (x/3) + 1;

        int startX = ptrX * 3 - 3;
        int lastX = ptrX * 3;

        int ptrY = (y/3) + 1;

        int startY = ptrY * 3 - 3;
        int lastY = ptrY * 3;

        boolean[] flag = new boolean[10];

        for (int i = startY ; i < lastY ; i++) {

            for (int j = startX ; j < lastX ; j++) {

                int val = arr[i][j];

                if (flag[val] == false)
                    flag[val] = true;
                else{
                    if (val != 0)
                        return false;
                }
            }
        }

        return true;
    }

}