본문으로 바로가기

[백트래킹] 스도쿠 2580 ○

category ps/브루트 포스 2021. 10. 21. 23:47

문제 해설 및 주의사항

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

 

빈 칸의 경우에는 0이 주어진다

 

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


(원래 스도쿠는 백트래킹으로 풀 수 없는 문제이지만, 입력의 특이성으로 백트래킹으로 풀이가 가능한 문제이다. )


 

풀이

1. 브루트 포스

- 빈 칸에 모든 수를 넣어본다.

 

2. 백트래킹

- 모든 수를 넣어보지 않고, 가능하지 않은 수 (겹치는 수)는 건너 뛴다.

 

3. 검사

- 행 / 열 / 3x3 정사각형 / 을 검사해야 한다.

- c[i][j] : i 행에 숫자 j 가 있으면 true

- c2[i][j] : i 열에 숫자 j 가 있으면 true

- c3[i][j] : i 번째 3x3 박스에 숫자 j 가 있으면 true

 

4. 함수 구조

 

- 기저 사례 

- 검사 / 백트래킹

- 다음(재귀)

- 원상복귀


풀이코드

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

using namespace std;

// 스도쿠 2580

int board[9][9];
/*
c[i][j] : i 행에 숫자 j 가 있으면 true
c2[i][j] : i 열에 숫자 j 가 있으면 true
c3[i][j] : i 번째 3x3 박스에 숫자 j 가 있으면 true
*/
bool c[9][10];
bool c1[9][10];
bool c2[9][10];

bool solve(int index){
	// 기저 사례 : 끝에 도달하면 출력
	if(index == 81){
		for(int i = 0; i < 9; i++){
			for(int j = 0; j < 9; j++){
				printf("%d ", board[i][j]);
			}
			printf("\n");
		}
		return true;
	}
	int x = index / 9, y = index % 9; 
	if(board[x][y] != 0 ){
		return solve(index + 1);
	}
	else{
		for(int i = 1; i <= 9; i++){
			int box = (x / 3)*3 + (y / 3);
			if(c[x][i] == false && c1[y][i] == false && c2[box][i] == false){
				c[x][i] = c1[y][i] = c2[box][i] = true;
				board[x][y] = i;
				if(solve(index + 1)){
					return true;
				}

				c[x][i] = c1[y][i] = c2[box][i] = false;
				board[x][y] = 0;
			}
		}
		
	}
	return false;
}

int main(){
	for(int i = 0; i < 9; i++){
		for(int j = 0; j < 9; j++){
			scanf("%d", &board[i][j]);
		}
	}
	fill_n(&c[0][0], 81, false);
	fill_n(&c1[0][0], 81, false);
	fill_n(&c2[0][0], 81, false);
	for(int i = 0; i < 9; i++){
		for(int j = 0; j < 9; j++){
			if(board[i][j] != 0){
				c[i][ board[i][j] ] = true;
				c1[j][ board[i][j] ] = true;
				int box = (j / 3) + (i / 3) * 3;
				c2[box][ board[i][j] ] = true;
			}
				
		}
	}
	solve(0);
	
}

 

퇴고

1. 배열 선언 시 인덱스 문제

- c c1 c2 배열은 각 행 / 열(0 ~ 8번 행 / 열) 및 박스를 검사하기 위함이었다. [i][j] 라면, i 번째 행 / 열 / 박스에 j 가 사용 되었는지 아닌지를 저장하는 배열이다. 그런데, 처음 선언시 [9][9] 라고 하여, j 의 범위인 1 ~ 9 를 충족시키지 못해서 예기치 못한 틀렸습니다가 자꾸 발생하였다.

반응형

'ps > 브루트 포스' 카테고리의 다른 글

[Leet code] 15. 3Sum  (0) 2021.11.26
[Leet code] 1. Two Sum  (0) 2021.11.26
[재귀] 에너지 모으기 16198  (0) 2021.10.17
[재귀] 두 동전 16197 ○  (0) 2021.10.16
[재귀] 연산자 끼워넣기 (2) 15658  (0) 2021.10.16