Posts 2239 sudoku
Post
Cancel

2239 sudoku

2239 sudoku

알고리즘(백트래킹)

1
2
3
4
1. 칸을 하나씩 탐방하면서, 0으로 기록돼있다면 수직, 수평, 3x3사각형을 검사하여 가능한 숫자를 하나씩 뽑아서 넣고 다음 칸 검사
2. 만약 0으로 기록되지않은 칸으로 갔다면 다음칸으로 넘겨주되, 마지막 칸일 경우 스도쿠가 완성된 것이므로 true를 반환한다.
3. 마찬가지로, 넣고 다음 칸으로 이동하는데, 마지막칸일 경우 스도쿠가 완성된 것이므로 true를 반환한다.
4. 최소일때를 반환하는 것이므로 먼저 검사하는 칸을 왼쪽 위로하고, 1부터 검사하여 가능한 걸 넣으면 된다.

구현

1
2
3
4
5
6
7
8
9
1. 내가 구현한 건 맨처음에 가능한 숫자를 먼저 뽑고, 그 가능한 숫자만 가지고 검사하고 넣고 빼고 했다.
2. 덕분에 시간이 좀 줄었지만, 체크하는데 매번 체크하여 시간이 좀 걸린 거 같다.
3. 체크하는 걸 좀 더 간결히 하는 방법은 각 칸마다 3개의 9개의 int원소를 가지는 배열을 가진다.
	ex) int checkMap[WIDTH][WIDTH][3][WIDTH+1];
 그리고 맨 처음에, 숫자를 넣었을 때마다 각각 수직, 수평, 3x3 사각형의 각 칸에 원래 가지고 있던 숫자 또는 넣은 숫자를 기록한다.
 수평일 경우 checmMap[row][col][0][value], 수직일 경우 checkMap[row][col][1][value], 사각형일경우 checkMap[row][col][2][value]
 이렇게하면 넣을 수 있는지 검사할 때 그냥 3개의 배열을 검사하여 있는지만 확인하면 되므로 더 간결해진다.
 또, 처음에 가능한 숫자를 먼저 뽑지 않아도 된다.  물론 false가 반환됐을 시, 다시 0으로 바꿔줄 필요도 있다.
-> 내일 해보자.

코드

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <iostream>
#include <cstring>
#include <cmath>
#define WIDTH 9

using namespace std;

int map[WIDTH][WIDTH];
int possibleNum[WIDTH][WIDTH][WIDTH+1];

void generatePossibleNum();
bool solveSudoku(int row, int col);
bool checkVertical(int row, int col, int value);
bool checkHorizontal(int row, int col, int value);
bool checkSquare(int row, int col, int value);

int main() {
	int input[WIDTH];
	for (int i = 0; i < WIDTH; i++)
			cin >> input[i];
	for (int i = 0; i < WIDTH; i++) {
		for (int j = WIDTH - 1; j >=0; j--) {
			map[i][j] = input[i] % 10;
			input[i] /= 10;
		}
	}
	generatePossibleNum();
	solveSudoku(0,0);

	for (int i = 0; i < WIDTH; i++) {
		for (int j = 0; j < WIDTH; j++)
			cout << map[i][j];
		cout << endl;
	}
}

void generatePossibleNum() {
	for (int i = 0; i < WIDTH; i++)
		for (int j = 0; j < WIDTH; j++)
			if (map[i][j] == 0) {
				for (int k = 1; k <= WIDTH; k++)
					possibleNum[i][j][k] = k;
				for (int vert = 0; vert < WIDTH; vert++)
					possibleNum[i][j][map[vert][j]] = 0;
				for (int horiz = 0; horiz < WIDTH; horiz++)
					possibleNum[i][j][map[i][horiz]] = 0;
			}

	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			int row = i * 3, col = j * 3;
			for (int r = 0; r < 3; r++) {
				for (int c = 0; c < 3; c++) {
					for (int r2 = 0; r2 < 3; r2++)
						for (int c2 = 0; c2 < 3; c2++)
							possibleNum[row + r][col + c][map[row + r2][col + c2]] = 0;
				}
			}
		}
	}
}

bool solveSudoku(int row, int col) {
	if (map[row][col] != 0) {
		if (col < WIDTH - 1)
			return solveSudoku(row, col + 1);
		else if (row < WIDTH - 1)
			return solveSudoku(row + 1, 0);
		else
			return true;
	}

	for (int i = 1; i <= WIDTH; i++) {
		if (possibleNum[row][col][i] != 0 && checkVertical(row, col, i) && checkHorizontal(row, col, i) && checkSquare(row, col, i)) {
			map[row][col] = i;
			if (col < WIDTH - 1) {
				if (solveSudoku(row, col + 1))
					return true;
			}
			else if (row < WIDTH - 1) {
				if (solveSudoku(row + 1, 0))
					return true;
			}
			else
				return true;
			map[row][col] = 0;
		}
	}
	return false;
}

bool checkVertical(int row, int col, int value) {
	for (int vert = 0; vert < WIDTH; vert++) {
		if (map[vert][col] == value)
			return false;
	}
	return true;
}
bool checkHorizontal(int row, int col, int value) {
	for (int horiz = 0; horiz < WIDTH; horiz++) {
		if (map[row][horiz] == value)
			return false;
	}
	return true;
}
bool checkSquare(int row, int col, int value) {
	int sr = row / 3, sc = col / 3;
	sr *= 3;
	sc *= 3;

	for (int r = 0; r < 3; r++) {
		for (int c = 0; c < 3; c++) {
			if (map[sr + r][sc + c] == value)
				return false;
		}
	}
	return true;
}
This post is licensed under CC BY 4.0 by the author.

2186 문자판

2252 줄세우기

Comments powered by Disqus.