#include <stdio.h>
#define RN 9
#define CN 13
//#include <intrin.h> //Visual C++용 __popcnt()함수 쓰기 위함
int sudoku[9][9]; //9x9 스도쿠판
int* r[9][9]; //스도쿠판의 행 우선 참조
int* c[9][9]; //스도쿠판의 열 우선 참조
int* s[9][9]; //스도쿠판의 3x3 섹터 우선 참조
int nums[1+ 9] = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 256 }; //1~9번 숫자를 비트로 표현
typedef int Set; //0~8비트 불리언, 9~12 rn, 13~17 cn
void init() { //참조 포인터 초기화
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
r[i][j] = c[j][i] = &sudoku[i][j];
for (int rn = 0; rn < 9; rn += 3)
for (int cn = 0; cn < 9; cn += 3)
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
s[rn + (cn / 3)][i * 3 + j] = &sudoku[rn + i][cn + j];
}
Set findAblNum(int rn, int cn) { //해당 칸의 가능한 숫자 세트 탐색
Set numset = 511; //0~8비트 true로 초기화
numset |= rn << RN;
numset |= cn << CN;
int sn = rn / 3 * 3 + cn / 3; //섹터 번호 구함
for (int i = 0; i < 9; i++) {
//행(*r),열(*c),섹터(*s) 탐색
if (*r[rn][i] > 0) //채워져 있으면
numset &= ~nums[*r[rn][i]]; //false로 마킹
if (*c[cn][i] > 0)
numset &= ~nums[*c[cn][i]];
if (*s[sn][i] > 0)
numset &= ~nums[*s[sn][i]];
}
return numset;
}
Set findMinPossible() { //가장 경우의 수가 적은칸의 세트 리턴
int size = 10;
Set minset = 170 << RN; //{10,10} 초기화
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (sudoku[i][j] > 0) continue; //채워진칸 무시
Set temp = findAblNum(i, j);
int nsize = __builtin_popcount(temp & 511); //__popcnt(temp&511); VC용
if (!nsize) //빈칸인데 가능한 숫자가 없으면
return 255 << RN; //오답 표시 리턴
else if (nsize == 1) //가능한 숫자가 하나일 경우 바로 리턴
return temp;
else if (nsize < size) {
size = nsize;
minset = temp;
}
}
}
return minset;
}
bool solve() {
Set set = findMinPossible(); //가장 경우의 수가 적은 칸 탐색
int rn = ((set >> RN) & 15);
int cn = ((set >> CN) & 15);
if (rn > 10)
return false;
if (rn == 10) //더 이상 빈칸이 없음을 뜻함.
return true; //풀린것!
for (int i = 1; i <= 9; i++) { //숫자 1~9를 채우는 부분
if (set & nums[i]) { //채울 수 있는 숫자이면
sudoku[rn][cn] = i; //숫자를 채움
if (solve()) //채운걸 풀어봄
return true; // 그게 풀렸으면 탈출
}
}
// 채울 수 있는 숫자가 없거나 다 채워봤는데 안된거니까
sudoku[rn][cn] = 0; //지우고
return false; //오답 리턴
}
int main() {
init(); //참조 포인터 초기화
char input[10]; //입력
//문자를 숫자로 변환
for (int i = 0; i < 9; i++) {
scanf("%s", input);
for (int j = 0; j < 9; j++)
sudoku[i][j] = input[j] - '0';
}
printf("%s\n", solve() ? "[Solved]" : "[No solution]"); //풀어
//결과 출력
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++)
printf("%d", sudoku[i][j]);
printf("\n");
}
}