알고리즘/BAEKJOON

[백준] 2239 스도쿠 (Java)

kyeee2 2022. 4. 6. 15:04

[2239 스도쿠]

난이도: 골드4

 

2239번: 스도쿠

스도쿠는 매우 간단한 숫자 퍼즐이다. 9×9 크기의 보드가 있을 때, 각 행과 각 열, 그리고 9개의 3×3 크기의 보드에 1부터 9까지의 숫자가 중복 없이 나타나도록 보드를 채우면 된다. 예를 들어 다

www.acmicpc.net

문제

입력

출력


[아이디어]

백트래킹을 사용하여 가지치기를 하였다.

처음에는 빈칸에 하나의 수를 결정할 때마다 for문을 통하여 가능한지의 여부를 찾았다. 시간초과가 뜨지 않았지만 다른 사람들이 시간을 훨씬 덜 쓰길래 찾아보았더니 for문을 사용하여 가능하지를 따지지 않고 따로 배열을 생성하여 체크하는 방법을 알게되었다. 

 

i행에 쓰인 숫자를 체크하는 배열 -> row[][]

i열에 쓰인 숫자를 체크하는 배열 -> col[][]

위의 그림처럼 사각형 안에 쓰인 숫자를 체크하는 배열 -> square[][]

이 때 몇 번째 square에 들어가는지는 (행 / 3) * 3 + (열 / 3) 으로 계산해주었다.


[JAVA 코드]

따로 배열을 만들어서 푼 방법

// 메모리: 17316KB
// 실행시간: 424ms

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class Solution {
	
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static StringBuilder output = new StringBuilder();
	
	static int N = 9;
	static boolean flag = true;
	static int [][] sudoku = new int [N][N];
	static boolean [][] row = new boolean [N][10];
	static boolean [][] col = new boolean [N][10];
	static boolean [][] square = new boolean [N][10];
	static List<Point> zeros = new ArrayList<>();
	
	static class Point {
		int r, c;
		
		public Point(int r, int c) {
			this.r = r;
			this.c = c;
		}
	}

	public static void main(String[] args) throws IOException {
		for(int r = 0; r < N; r++) {
			String line = br.readLine();
			for(int c = 0; c < N; c++) {
				sudoku[r][c] = line.charAt(c) - '0';
				if(sudoku[r][c] == 0) zeros.add(new Point(r, c));
				else {
					row[r][sudoku[r][c]] = true;
					col[c][sudoku[r][c]] = true;
					square[(r / 3) * 3 + (c / 3)][sudoku[r][c]] = true;
				}
			}
		}
		
		dfs(0);
		System.out.println(output);
	}

	private static void dfs(int idx) {
		if(!flag) return;
		if(idx == zeros.size()) {
			for(int r = 0; r < N; r++) {
				for(int c = 0; c < N; c++) {
					output.append(sudoku[r][c]);
				}
				output.append("\n");
			}
			flag = false;
			
			return;
		}
		
		int r = zeros.get(idx).r;
		int c = zeros.get(idx).c;
		
		for(int n = 1; n < 10; n++) {
			if(!row[r][n] && !col[c][n] && !square[(r / 3) * 3 + (c / 3)][n]) {
				sudoku[r][c] = n;
				row[r][n] = true;
				col[c][n] = true;
				square[(r / 3) * 3 + (c / 3)][n] = true;
				dfs(idx + 1);
				sudoku[r][c] = 0;
				row[r][n] = false;
				col[c][n] = false;
				square[(r / 3) * 3 + (c / 3)][n] = false;
			}
		}
	}
}

 

처음에 따로 배열을 만들지 않고 푼 방법

더보기
// 메모리: 21308KB
// 실행시간: 852ms

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class Solution {
	
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static StringBuilder output = new StringBuilder();
	
	static int N = 9;
	static boolean flag = true;
	static int [][] sudoku = new int [N][N];
	static List<Point> zeros = new ArrayList<>();
	
	static class Point {
		int r, c;
		
		public Point(int r, int c) {
			this.r = r;
			this.c = c;
		}
	}

	public static void main(String[] args) throws IOException {
		for(int r = 0; r < N; r++) {
			String line = br.readLine();
			for(int c = 0; c < N; c++) {
				sudoku[r][c] = line.charAt(c) - '0';
				if(sudoku[r][c] == 0) zeros.add(new Point(r, c));
			}
		}
		
		dfs(0);
		System.out.println(output);
	}

	private static void dfs(int idx) {
		if(!flag) return;
		if(idx == zeros.size()) {
			for(int r = 0; r < N; r++) {
				for(int c = 0; c < N; c++) {
					output.append(sudoku[r][c]);
				}
				output.append("\n");
			}
			flag = false;
			
			return;
		}
		
		int r = zeros.get(idx).r;
		int c = zeros.get(idx).c;
		
		for(int n = 1; n < 10; n++) {
			sudoku[r][c] = n;
			if(isPossible(r, c)) {
				dfs(idx + 1);
			}
			sudoku[r][c] = 0;
		}
	}
	
    // 이 부분이 시간을 많이 잡아먹는다
	private static boolean isPossible(int r, int c) {
		// 사각형
		for(int i = 0; i < 3; i++) {
			for(int j = 0; j < 3; j++) {
				if(r - r % 3 + i == r && c - c % 3 + j == c) continue;
				if(sudoku[r - r % 3 + i][c - c % 3 + j] == sudoku[r][c]) return false;
			}
		}
		
		// 가로
		for(int i = 0; i < N; i++) {
			if(c == i) continue;
			if(sudoku[r][i] == sudoku[r][c]) return false;
		}
		
		// 세로
		for(int i = 0; i < N; i++) {
			if(r == i) continue;
			if(sudoku[i][c] == sudoku[r][c]) return false;
		}
		
		return true;
	}

}