PS(Problem Solving)/백준(BOJ)

[2239번][C/C++] 스도쿠

seongmik 2023. 2. 2. 16:16
728x90
반응형

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

 

2239번: 스도쿠

스도쿠는 매우 간단한 숫자 퍼즐이다. 9×9 크기의 보드가 있을 때, 각 행과 각 열, 그리고 9개의 3×3 크기의 보드에 1부터 9까지의 숫자가 중복 없이 나타나도록 보드를 채우면 된다. 예를 들어 다

www.acmicpc.net

미완성된 스도쿠 판이 입력으로 주어질 때, 스도쿠판을 완성해서 출력하는 문제이다.

 

이 문제는 일단 N-Queen과 굉장히 유사하다.

N-Queen문제를 생각해보면 보드에서 모든 자리를 살펴보는데 각 자리에 대해서 queen을 놓을 수 있는지 없는지 판단한 뒤, 놓을 수 있는 경우에는 놓고 지나거나 안 놓고 지나가고, 놓을 수 없는 경우에는 안놓고 지나간다.

 

이러한 백트래킹은 다음과 같은 논리구조로 구성된다.

     1. 지금 내가 있는 칸에서 하고자하는 걸 할 수 있는 조건이 되는가?

           1-1) YES : 하고 지나가는 경우와 안 하고 지나가는 경우, 두가지를 재귀적으로 탐색한다.

           1-2) NO : 무조건 안 하고 지나간다.

 

이러한 논리구조는 N-Queen문제 뿐 아니라, 이 스도쿠 문제에서도 그대로 적용된다.

 

여기서 생각해볼만한 점은 어떻게 지금 내 위치에서 어떤 수를 놓을 수 있는지 없는지 체크할 것인가? 라는 문제이다.

이는 3가지 테스트에 대해서 통과하면된다.

        1. 지금 보드에서의 내 위치의 정사각형 모양의 네모 칸에 지금 내가 넣으려는 수와 중복된 수가 없어야한다.

        2. 지금 보드에서 내 y좌표에서 모든 x위치의 칸에 지금 내가 넣으려는 수와 중복된 수가 없어야한다.

        3. 지금 보드에서 내 x좌표에서 모든 y위치의 칸에 지금 내가 넣으려는 수와 중복된 수가 없어야한다.

 

이 테스트를 통과하면 이제 재귀적으로 지금 수를 넣고 지나가거나 안넣고 다른 수를 테스트하거나 할 수 있다.

이후는 구현력의 문제이다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;

int map[11][11];
bool flag;

void input()
{
    for (int i = 0; i < 9; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            char inp;
            scanf("%c", &inp);

            map[i][j] = inp - '0';
        }
        getchar();
    }
}

void print()
{
    for (int i = 0; i < 9; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            printf("%d", map[i][j]);
        }
        printf("\n");
    }
}

bool test(int y, int x, int num)
{
    int baseY = (y / 3) * 3;
    int baseX = (x / 3) * 3;

    // TEST FOR SQUARE
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            if (map[baseY + i][baseX + j] == num)
                return false;
        }
    }

    // TEST FOR VERTICAL, HORIZONTAL LINE
    for (int i = 0; i < 9; i++)
    {
        if (map[i][x] == num || map[y][i] == num)
            return false;
    }

    // TEST PASSED
    return true;
}

void backTracking(int y, int x)
{
    // BASE CASE
    if (flag)
        return;
    if (y == 9 && x == 0)
    {
        print();
        flag = true;
        return;
    }

    if (map[y][x] != 0)
    {
        // BACK TRACKING : CASE 1
        if (x == 8)
            backTracking(y + 1, 0);
        else
            backTracking(y, x + 1);
        if (flag)
            return;
    }
    else
    {
        // BACKTRACKING : CASE 2
        for (int i = 1; i <= 9; i++)
        {
            if (test(y, x, i))
            {
                map[y][x] = i;
                if (x == 8)
                    backTracking(y + 1, 0);
                else
                    backTracking(y, x + 1);
                if (flag)
                    return;
                map[y][x] = 0;
            }
        }
    }
}

int main()
{
    input();

    backTracking(0, 0);
    return 0;
}
728x90
반응형

'PS(Problem Solving) > 백준(BOJ)' 카테고리의 다른 글

[1958번][C/C++] LCS 3  (0) 2023.06.27
[1550번][C/C++] 16진수  (1) 2023.02.03
[1038번][C/C++] 감소하는 수  (0) 2023.02.01
[2342번][C/C++] Dance Dance Revolution  (0) 2023.01.31
[2665번][C/C++] 미로만들기  (0) 2023.01.30