티스토리 뷰

728x90

문제

스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루어진 정사각형 판 위에서 이뤄지는데, 게임 시작 전 일부 칸에는 1부터 9까지의 숫자 중 하나가 쓰여 있다.

나머지 빈 칸을 채우는 방식은 다음과 같다.

  1. 각각의 가로줄과 세로줄에는 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
  2. 굵은 선으로 구분되어 있는 3x3 정사각형 안에도 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.

위의 예의 경우, 첫째 줄에는 1을 제외한 나머지 2부터 9까지의 숫자들이 이미 나타나 있으므로 첫째 줄 빈칸에는 1이 들어가야 한다.

또한 위쪽 가운데 위치한 3x3 정사각형의 경우에는 3을 제외한 나머지 숫자들이 이미 쓰여있으므로 가운데 빈칸에는 3이 들어가야 한다.

이와 같이 빈 칸을 차례로 채워 가면 다음과 같은 최종 결과를 얻을 수 있다.

게임 시작 전 스도쿠 판에 쓰여 있는 숫자들의 정보가 주어질 때 모든 빈칸이 채워진 최종 모습을 출력하는 프로그램을 작성하시오.

 

입력

아홉 줄에 걸쳐 한 줄에 9개씩 게임 시작 전 스도쿠판 각 줄에 쓰여 있는 숫자가 한 칸씩 띄워서 차례로 주어진다. 스도쿠 판의 빈칸의 경우에는 0이 주어진다. 스도쿠 판을 규칙대로 채울 수 없는 경우의 입력은 주어지지 않는다.

 

출력

모든 빈 칸이 채워진 스도쿠 판의 최종 모습을 아홉 줄에 걸쳐 한 줄에 9개씩 한 칸씩 띄워서 출력한다.

스도쿠 판을 채우는 방법이 여럿인 경우는 그중 하나만을 출력한다.

 

제한

  • baekjoon의 백트래킹 알고리즘으로 풀 수 있는 입력만 주어진다. 다음은 그 알고리즘의 수행 시간이다.
    • C++14: 80ms
    • Java: 292ms
    • PyPy3: 1172ms

 

코드

#include <iostream>
#include <vector>

using namespace std;

int board[9][9];
bool check_r[9][10];	// check_r[i][j]는 i번 행에 j라는 숫자가 있는지
bool check_c[9][10];	// check_c[i][j]는 i번 열에 j라는 숫자가 있는지
bool check_box[9][10];	// check_box[i][j]는 i번 박스에 j라는 숫자가 있는지
bool done;		// 정답을 찾았는지

// board[r][c]에 i라는 숫자를 넣거나 삭제함
void set_flag(int r, int c, int i, bool flag)
{
	if (flag)
		board[r][c] = i;
	else
		board[r][c] = 0;
	check_r[r][i] = flag;
	check_c[c][i] = flag;
	check_box[r / 3 * 3 + c / 3][i] = flag;
}

void print()
{
	int i, j;

	for (i = 0; i < 9; i++)
	{
		for (j = 0; j < 9; j++)
		{
			cout << board[i][j] << " ";
		}
		cout << endl;
	}
}

void dfs(int num)
{
	int r, c, i;

	if (done)		// 이미 정답을 발견했다면 바로 리턴
		return;
	r = num / 9;		// num번 칸의 행 번호
	c = num % 9;		// num번 칸의 열 번호
	if (num == 81)		// 모든 칸을 채웠다면 출력하고 리턴
	{
		done = true;
		print();
		return;
	}
	if (!board[r][c])	// 빈칸인 경우 1~9의 숫자 중 이 칸이 포함되는 행, 열, 박스에 없는 숫자를 넣음
	{			// dfs로 가능한 경우인지 확인 후 다시 칸을 비움 (다른 경우를 확인하기 위해)
		for (i = 1; i <= 9; i++)
		{
			if (!check_r[r][i] && !check_c[c][i] && !check_box[r / 3 * 3 + c / 3][i])
			{
				set_flag(r, c, i, true);
				dfs(num + 1);
				set_flag(r, c, i, false);
			}
		}
	}
	else			// 이미 숫자가 있는 칸이라면 바로 다음 칸을 확인함
	{
		dfs(num + 1);
	}
}

int main()
{
	int i, j, num;

	// 입력받을 때 check_ 배열에도 표시함
	for (i = 0; i < 9; i++)
	{
		for (j = 0; j < 9; j++)
		{
			cin >> num;
			board[i][j] = num;
			check_r[i][num] = true;
			check_c[j][num] = true;
			check_box[i / 3 * 3 + j / 3][num] = true;
		}
	}
    	// 첫 번째 칸부터 확인
	dfs(0);	
	return 0;
}

 

입력을 받을 때 check_ 배열에 각각의 행, 열, 3 X 3 박스에 해당 인덱스의 숫자가 있는지 표시한다. 3 X 3 박스의 번호는 i / 3 * 3 + j / 3의 식으로 구할 수 있다.

이후 첫 번째 칸부터 확인하며 빈칸인 경우 가능한 숫자를 대입해보는 방식을 통해 가능한 경우인지 확인한다. 만약 모든 칸이 올바르게 채워졌다면 board를 출력한다. 이때 done을 true로 설정하여 더 이상 탐색하지 않게 함으로써 최초에 발견한 하나의 답만 출력할 수 있다.

 

링크

 

2580번: 스도쿠

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

www.acmicpc.net

 

inbdni/Baekjoon

Contribute to inbdni/Baekjoon development by creating an account on GitHub.

github.com

 

728x90
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
공지사항
링크
Total
Today
Yesterday