Algorithm/Backtracking

BOJ#2580 스도쿠

밤이2209 2017. 3. 23. 16:59

BOJ#2580 스도쿠


* 문제

* 풀이
스도쿠는 어떻게 푸는 것일까요?
사람이 스도쿠를 푸는 과정을 생각해보면 아래와 같습니다.(Backtracking) 

숫자를 하나 검증해서 넣어보고 -> 다른 칸으로 진행 -> 실패하면 되돌아와서 다른 숫자를 넣어보고 -> 반복..

계산량을 줄이기 위해 최초 map 정보를 입력 받을 때 필요한 정보들을 미리 저장해두면 됩니다.
1. 빈칸의 정보를 저장한다.
2. 각 행의 정보를 저장한다.
3. 각 열의 정보를 저장한다.
4. 각 사각형의 정보를 저장한다.

자료구조는 boolean 배열로 해도 되고, bit mask를 이용해도 됩니다.



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

/**
* BOJ#2580 스도쿠
* https://www.acmicpc.net/problem/2580
*/

public class Main {

static int[][] map = new int[9][9]; // 스도쿠 맵
static int[] rowInfo = new int[9]; // 각 행의 상태 정보
static int[] colInfo = new int[9]; // 각 열의 상태 정보
static int[] squareInfo = new int[9]; // 각 사각형의 상태 정보
static int blankCnt = 0; // 빈칸 개수

public static void main(String[] args) throws IOException {

ArrayList<Point> blankArr = new ArrayList<>(); // 빈칸 정보를 저장하고 있는 ArrayList

// input
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

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

StringTokenizer st = new StringTokenizer(br.readLine());

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

int num = Integer.parseInt(st.nextToken());
int squareNum = (row / 3) + (col / 3) * 3;

map[row][col] = num;

// 0의 위치를 저장한다
if (num == 0) {

blankArr.add(new Point(row, col, squareNum));
}
// 행, 열, square 정보를 기록한다
else {

rowInfo[row] |= 1 << num;
colInfo[col] |= 1 << num;
squareInfo[squareNum] |= 1 << num;
}
}
}

// solve
blankCnt = blankArr.size();
backtracking(0, blankCnt, blankArr);

}

static void backtracking(int idx, int blankCnt, ArrayList<Point> blankArr) {

if (idx == blankCnt) {

printSudoku();
return;
}

int row = blankArr.get(idx).row;
int col = blankArr.get(idx).col;
int squareNum = blankArr.get(idx).squareNum;

for (int num = 1; num <= 9; num++) {

if (!isPossibleValue(num, row, col, squareNum)) {

continue;
}

saveInfo(num, row, col, squareNum);
backtracking(idx + 1, blankCnt, blankArr);
restoreInfo(num, row, col, squareNum);
}
}

static boolean isPossibleValue(int num, int row, int col, int squareNum) {

int info = 1 << num;

// row check
if ((rowInfo[row] & info) == info) {

return false;
}

// column check
if ((colInfo[col] & info) == info) {

return false;
}

// square check
if ((squareInfo[squareNum] & info) == info) {

return false;
}

return true;
}

static void saveInfo(int num, int row, int col, int squareNum) {

int info = 1 << num;

map[row][col] = num;

rowInfo[row] |= info;
colInfo[col] |= info;
squareInfo[squareNum] |= info;
}

static void restoreInfo(int num, int row, int col, int squareNum) {

int info = 1 << num;

map[row][col] = 0;

rowInfo[row] &= ~info;
colInfo[col] &= ~info;
squareInfo[squareNum] &= ~info;
}

static void printSudoku() {

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

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

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

class Point {

int row;
int col;
int squareNum;

Point(int row, int col, int squareNum) {

this.row = row;
this.col = col;
this.squareNum = squareNum;
}
}





'Algorithm > Backtracking' 카테고리의 다른 글

BOJ#1405 미친 로봇  (0) 2017.03.16
BOJ#2661 좋은수열  (0) 2017.03.16
BOJ#9663 N-Queen  (0) 2016.11.11