https://www.acmicpc.net/problem/2580
문제조건
- 스도쿠판을 채우자
- 각각의 가로줄과 세로줄에는 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
- 굵은 선으로 구분되어 있는 3x3 정사각형 안에도 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
접근방법
문제를 보자마자 떠오른 생각은 N-Queen 문제와 상당히 유사한 문제라는 생각 이었다. 물론 Brute Force로 모든 경우의 수를 탐색해서 구할 수도 있겠지만, O(2^n) 이상의 시간소요로 시간초과가 날 것이 분명했고, N-Queen문제와 같이 백트래킹으로 접근했다.
유망한지 판단하고, 유망하다면 DFS를 진행하는 백트래킹 방식에서 시간단축이 됨을 인지하고, 가로, 세로, 3x3 크기의 칸에서 같은 숫자가 하나도 없는지 체크하고 그러면 유망한것으로 판단하고 DFS를 진행하도록 했다.
#include <iostream>
#include <vector>
using namespace std;
int map[10][10];
vector<pair<int, int> > v;
bool judge = false;
int res;
bool promising(pair<int ,int> p) {
int x = p.first;
int y = p.second;
int divide_x = x / 3;
int divide_y = y / 3;
// 직선검사
for (int i = 0; i < 9; i++) {
if (map[x][i] == map[x][y] && i != y) return false;
if (map[i][y] == map[x][y] && i != x) return false;
}
// 3x3 칸 검사
for (int i = 3 * divide_x; i < 3 * divide_x + 3; i++)
for (int j = 3 * divide_y; j < 3 * divide_y + 3; j++)
if (map[i][j] == map[x][y] && i != x && j != y) return false;
return true;
}
void dfs(int n) {
if (n == res) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
cout << map[i][j] << " ";
}
cout << '\n';
}
judge = true;
return;
}
for (int i = 1; i <= 9; i++) {
map[v[n].first][v[n].second] = i;
if (promising(v[n])) dfs(n + 1);
if (judge) return;
}
map[v[n].first][v[n].second] = 0;
return;
}
int main() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
cin >> map[i][j];
if (map[i][j] == 0) {
v.push_back({ i,j });
res++;
}
}
}
dfs(0);
}
백트래킹의 정석같은 느낌의 문제였다.
'Algorithm > Back Tracking' 카테고리의 다른 글
[BAEKJOON] 17136번 색종이 붙이기 (0) | 2024.04.27 |
---|---|
[BAEKJOON] 14889번 스타트와 링크 (0) | 2024.04.08 |