알고리즘/문제 풀이

2580번: 스도쿠

Themion 2021. 12. 17. 11:29

https://www.acmicpc.net/problem/2580

 

2580번: 스도쿠

스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루

www.acmicpc.net

백트래킹을 이용해 가능한 모든 수를 빈 칸에 넣어보고, 모든 수를 다 넣는 데에 성공했다면 그 결과를, 실패했다면 -1을 출력한다.

#include <cstdio>

// row[i][j]: i번째 행에 j가 들어있다면 true, 아니라면 false
// col[i][j]: i번째 열에 j가 들어있다면 true, 아니라면 false
// blk[i][j][k]: [i][j]번째 3*3짜리 블록에 k가 들어있다면 true, 아니라면 false
bool row[9][10], col[9][10], blk[3][3][10];
// 스도쿠 판을 저장할 공간
int sudoku[9][9];

bool valid(int y, int x, int i) {
    return !row[y][i] && !col[x][i] && !blk[y / 3][x / 3][i];
}

//칸 (x, y)에 val을 넣거나 빼고 이를 표시
void set(int x, int y, int val, bool b_set) {
    sudoku[x][y] = b_set ? val : 0;
    row[x][val] = col[y][val] = blk[x / 3][y / 3][val] = b_set;
}

bool fill(int idx) {
    // 모든 값에 가능한 값이 들어갔다면 true를 반환한다
    if (idx == 81) return true;
    // 현재 확인한 칸에 값이 이미 있다면 다음 칸으로 넘어간다
    else if (sudoku[idx / 9][idx % 9] != 0) return fill(idx + 1);

    // x, y: 현재 칸의 좌표
    int y = idx / 9, x = idx % 9;

    // 칸 (x, y)의 가능한 모든 값 i에 대해
    for (int i = 1; i <= 9; i++ ) if (valid(y, x, i)) {
        // i를 해당 칸에 넣은 뒤 이를 표시하고
        set(y, x, i, true);
        // 해당 경우가 답이 될 수 있다면 true를 반환한다
        if (fill(idx + 1)) return true;
        // 그렇지 않다면 i를 제거한 뒤 이를 표시한다
        else set(y, x, i, false);
    }

    // 가능한 경우가 하나도 없다면 false를 반환한다
    return false;
}

int main() {
    // flag: 입력된 경우가 가능하다면 true, 아니라면 false
    bool flag = true;
    // buf: 입력에 사용할 공간
    int buf;

    // 스도쿠의 각 칸에 대해
    for (int i = 0; i < 9; i++) for (int j = 0; j < 9; j++) {
        // 해당 칸의 값을 입력한 뒤
        scanf("%d", &buf);
        // 해당 값이 스도쿠의 규칙에 어긋나는 값이라면 false를 반환
        if (!valid(i, j, buf)) flag = false;
        // 그렇지 않다면 현재 칸이 해당된 행, 열, 블록에 val이 등장했음을 표시한다
        else if (buf) set(i, j, buf, true);
    }

    // 만일 주어진 스도쿠 판에 맞게 모든 값을 입력했다면
    // 스도쿠 판을 양식에 맞게 출력한다
    if (flag && fill(0)) for (int i = 0; i < 9; i++)  for (int j = 0; j < 9; j++)
        printf("%d%c", sudoku[i][j], (i < 8 ? ' ' : '\n'));
    // 그렇지 않다면 -1을 출력한다
    else printf("-1\n");

    return 0;
}

'알고리즘 > 문제 풀이' 카테고리의 다른 글

2588번: 곱셈  (0) 2021.12.17
2581번: 소수  (0) 2021.12.17
2579번: 계단 오르기  (0) 2021.12.17
2577번: 숫자의 개수  (0) 2021.12.17
2562번: 최댓값  (0) 2021.12.17