https://www.acmicpc.net/problem/2239
[필자 사고]
백트래킹 및 구현 문제다.
ㅇㅣ 문제만의 독특한 매력은 0인 구간을 idx로 따로 넣어서 해당 idx관련 백트래킹만 수행하면 된다.
각 for문 범위는 1~9라는 숫자들을 넣은 형태로 백트래킹을 수행한다.
또한 필자가 개인적으로 배운 기술은 int startSero 처리 로직이다.
특정 인덱스의 시작과 끝을 알려면
int startSero = sero/3*3 을 하게 되면 원하는 시작 idx를 바로 구할 수 있었다.
옛날에는 하드코딩 했었는데 좋은 배움이 되었다.
[코드 해설]
vector<vector<int>> arr
- 9×9 스도쿠 보드를 저장하는 2차원 벡터입니다.
- 각 요소는 0~9의 숫자 중 하나를 저장하며, 0은 빈 칸을 의미합니다.
vector<pair<int, int>> idxArr
- 스도쿠 보드에서 0으로 비어 있는 칸의 좌표들을 저장하는 리스트입니다.
- 백트래킹 시 이 리스트의 인덱스를 따라 빈 칸을 순차적으로 채웁니다.
void Input()
- 표준 입력으로 9줄의 문자열(숫자 9개)을 받아서 arr에 숫자로 저장합니다.
- 동시에 숫자가 0인 칸의 좌표를 idxArr에 저장해둡니다.
- 입력값이 문자열이므로 str[k] - '0'으로 정수 변환합니다.
- arr.assign(9, vector<int>(9))을 통해 9×9 배열로 초기화합니다.
bool isValid(int sero, int garo, int num)
- 주어진 (sero, garo) 좌표에 num을 넣었을 때 스도쿠 규칙을 만족하는지 검사합니다.
- 가로(행), 세로(열), 그리고 3×3 박스에 동일한 숫자가 존재하면 false를 반환합니다.
- 조건을 모두 통과하면 true를 반환합니다.
bool firstFlag
- 해를 찾은 뒤 더 이상 탐색하지 않도록 하는 플래그입니다.
- 첫 번째 정답만 출력하고 탐색을 멈추기 위해 사용됩니다.
void Print()
- 현재 보드 상태인 arr를 9줄로 출력합니다.
- 각 줄에는 9개의 숫자가 붙어서 출력됩니다.
void backTracking(int idx)
- 백트래킹 알고리즘의 핵심 함수입니다.
- idxArr의 idx번째 빈 칸에 대해 1~9 중 가능한 숫자를 하나씩 시도합니다.
- isValid()로 숫자가 유효한지 검사하고, 유효하면 보드에 넣고 재귀 호출합니다.
- 이후 다시 0으로 되돌려 백트래킹을 수행합니다.
- idx == idxArr.size()가 되면 모든 빈 칸이 채워졌으므로 정답을 출력하고 firstFlag = true로 탐색을 중지합니다.
void Game_Start()
- 백트래킹 탐색을 시작하는 진입 함수입니다.
- 항상 backTracking(0)으로 시작합니다.
int main()
- 프로그램의 시작점입니다.
- Input()을 호출해 데이터를 입력받고, Game_Start()로 스도쿠 풀이를 시작합니다.
[소스 코드]
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
vector<vector<int>> arr;
vector<pair<int, int>> idxArr;
void Input() {
arr.assign(9, vector<int>(9));
for (int i = 0; i < 9; i++) {
string str;
cin >> str;
for (int k = 0; k < str.size(); k++) {
arr[i][k] = str[k]-'0';
if (arr[i][k]==0)idxArr.push_back({ i,k });
}
}
}
bool isValid(int sero, int garo, int num) {
for (int i = 0; i < 9; i++) {
if (arr[sero][i] == num)return false;
}
for (int i = 0; i < 9; i++) {
if (arr[i][garo] == num)return false;
}
int startSero = sero / 3 * 3;
int startGaro = garo / 3 * 3;
for (int i = startSero; i < startSero + 3; i++) {
for (int k = startGaro; k < startGaro + 3; k++) {
if (arr[i][k] == num)return false;
}
}
return true;
}
bool firstFlag = false;
void Print() {
for (int i = 0; i < 9; i++) {
for (int k = 0; k < 9; k++) {
cout << arr[i][k];
}
cout << "\n";
}
}
void backTracking(int idx) {
if (firstFlag) return;
if (idx == idxArr.size()) {
Print();
firstFlag = true;
return;
}
int sero = idxArr[idx].first;
int garo = idxArr[idx].second;
for (int i = 1; i <= 9; i++) {
if (isValid(sero, garo, i) == false)continue;
arr[sero][garo] = i;
backTracking(idx + 1);
arr[sero][garo] = 0;
}
}
void Game_Start() {
backTracking(0);
}
int main(void) {
Input();
Game_Start();
}