반응형

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

 

서론

정답이 여러개가 나오면 전부 출력을 하는 문제가 있었는데, 발견이 쉽지 않았다.

다른분들의 코드에서 'exit(0)'을 발견하고 알아낼 수 있었다.

 


풀이

이 문제는 DFS 문제다.

처음 만나는 0의 좌표에 1~9까지 각각 넣어보고 조건에 맞으면 두번째 만나는 0도 1~9까지 넣어보고 이를 반복하다가 마지막에 만나는 0도 1~9까지 중 하나를 넣었더니 답을 만족하면 출력한다.

만약 두번째 만나는 0을 1~9까지 전부 넣어봤는데 조건에 맞는게 없다면 첫번째 만난 0에서 값을 잘못 넣은 것이므로 리턴하는 방식이다.

 

조건은 3개가 주어지는데 셋 다 함수로 만들고 리턴값은 boolean으로 줬다. 세 함수의 리턴값이 전부 true면 조건에 만족하므로 값을 넣으면 된다.

각 함수는 가로, 세로, 사각형에 안에 현재값과 같은 값이 존재하면 false를 리턴한다.

 

마지막 0까지 조건에 맞는 값을 넣었으면 출력을 해야하는데, 출력 후 그냥 return시키면 또 다른 정답이 있는지 계속 탐색하므로 강제로 프로그램을 종료해야한다.

 

스도쿠 값을 입력받을떄 0은 따로 벡터에 좌표를 저장해서 DFS에서 전 범위를 탐색하지 않게 했다.

 


구현

//c++

#pragma warning(disable:4996)
#include <vector>
#include <iostream>
#include <cstdio>

int map[10][10];
int zeroCnt;
std::vector<std::pair<int, int>>v;

void input() {
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			int x;
			scanf("%d", &x);
			if (x == 0) {
				v.push_back({ i, j }); 
				zeroCnt++;
			}
			else map[i][j] = x;
		}
	}
}

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

bool checkWidth(int y, int x, int value) {
	for (int i = 0; i < 9; i++) {
		if (map[y][i] == value) return false;
	}
	return true;
}

bool checkHeight(int y, int x, int value) {
	for (int i = 0; i < 9; i++) {
		if (map[i][x] == value) return false;
	}
	return true;
}

bool checkSquare(int y, int x, int value) {
	int startY = y - y % 3;
	int startX = x - x % 3;
	for (int i = startY; i < startY + 3; i++) {
		for (int j = startX; j < startX + 3; j++) {
			if (map[i][j] == value) return false;
		}
	}
	return true;
}

void dfs(int cnt) {
	if (cnt == zeroCnt) { 
		output();
		exit(0);
	}
	int y = v[cnt].first;
	int x = v[cnt].second;

	for (int i = 1; i <= 9; i++) {
		if (checkWidth(y, x, i) == true && checkSquare(y, x, i) == true && checkHeight(y, x, i) == true) {
			map[y][x] = i;
			dfs(cnt + 1);
			map[y][x] = 0;
		}
	}	
	return;
}

int main() {
	input();
	dfs(0);
}