문제

스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루어진 정사각형 판 위에서 이뤄지는데, 게임 시작 전 몇 몇 칸에는 1부터 9까지의 숫자 중 하나가 쓰여 있다.

 

입력

아홉 줄에 걸쳐 한 줄에 9개씩 게임 시작 전 스도쿠판 각 줄에 쓰여 있는 숫자가 한 칸씩 띄워서 차례로 주어진다. 스도쿠 판의 빈 칸의 경우에는 0이 주어진다. 스도쿠 판을 규칙대로 채울 수 없는 경우의 입력은 주어지지 않는다.

출력

모든 빈 칸이 채워진 스도쿠 판의 최종 모습을 아홉줄에 걸쳐 한 줄에 9개씩 한 칸씩 띄워서 출력한다.

스도쿠 판을 채우는 방법이 여럿인 경우는 그 중 하나만을 출력한다.

 

문제 풀이

 스도쿠의 규칙은 가로, 세로, 3*3 박스 내에서 같은 값이 없는 1~9 숫자를 넣어서 전체 표를 완성하는 놀이. 여기서 공백이 있는 칸(문제에서는 0)을 가로 세로 박스내에서 체크해서 넣을 수 있는 값을 넣고 다음 빈칸으로 이동하기를 반복 전체 표가 완성되면 출력하도록 했다. DFS 방식으로 접근해서 문제를 풀었는데, 풀고나서 든 생각은 빈칸을 전부 큐에 넣어놓고 하나씩 꺼내가며 가로 세로 3*3박스 내에서 일치하는 값이 없는 확정적인 빈칸에만 값을 넣고, 불확실한 값(여러 값을 넣을 수 있는 경우) 에는 다시 큐에 집에넣는 방식으로 해도 문제가 풀릴거 같다. 어떤 풀이가 더 빠를지는 구현 후 비교해보아야 겠는데, 생각보다 이 코드도 작성하는데 시간이 많이 걸렸어서 큐를 사용한 방식은 해보고 수정하기로..

 

코드

import java.util.*;
import java.io.*;

public class Main {
    public static int[][] arr = new int[10][10];
    public static List<Point> list = new ArrayList<>();
    
    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;
        
        for(int i=1; i<=9; i++) {
            st = new StringTokenizer(br.readLine());
            for(int j=1; j<=9; j++) {
                arr[i][j] = Integer.parseInt(st.nextToken());
                if(arr[i][j]==0) {
                    list.add(new Point(i,j));
                }
            }
        }
        
        recur(0);
        
        StringBuilder sb = new StringBuilder();
        for(int i=1; i<10; i++) {
            for(int j=1; j<10; j++) {
                sb.append(arr[i][j]+" ");
            }
            sb.append("\n");
        }
        
        bw.write(sb.toString());
        bw.flush();
    }
    
    public static boolean recur(int idx) {
        if(idx==list.size()) {
            return true;
        }
        Point temp = list.get(idx);
        for(int i=1; i<10; i++) {
            if(!checkMap(temp.y, temp.x,i))
                continue;
            arr[temp.y][temp.x] = i;
            boolean flag = recur(idx+1);
            if(flag) return true;
            arr[temp.y][temp.x] = 0;
        }
        
        return false;
    }
    
    public static boolean checkMap(int y, int x, int num) {
        for(int i =1; i<10; i++) {
            if(arr[y][i]==num || arr[i][x]==num)
                return false;
        }
        
        for(int i = ((y-1)/3)*3+1; i<((y-1)/3)*3+4; i++) {
            for(int j = ((x-1)/3)*3+1; j<((x-1)/3)*3+4; j++) {
                if(arr[i][j]==num)
                    return false;
            }
        }
        return true;
    }  
}

class Point {
    int x;
    int y;
    Point(int y, int x) {
        this.x = x;
        this.y = y;
    }
}  

'Baekjoon-Algorithm > 백트래킹' 카테고리의 다른 글

백준 9663 N-Queen java 풀이  (0) 2020.08.24

+ Recent posts