그럴듯한 개발 블로그
article thumbnail
Published 2023. 12. 15. 19:02
백준 2580 스도쿠 c++ <algorithm>/백준
반응형

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

 

2580번: 스도쿠

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

www.acmicpc.net

처음 풀이 : 레퍼런스로 넘기고 set 사용 때문에 시간 초과 난 것 같다.

// 스도쿠 시간초과;
#include <iostream>
#include <vector>
#include <set>

using namespace std;

vector<vector<int> > board(9, vector<int>(9, 0));
vector<pair<int, int> > empty_xy;

// 0 1 2  3 4 5  6 7 8
void eraseInvalidNum(int x, int y, set<int>& s) {
	int start_x = x / 3 * 3, start_y = y / 3 * 3;
	// 3 x 3 박스
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			int n = board[start_x + i][start_y + j];
			if (s.find(n) != s.end())
				s.erase(n);
		}
	}
	// 가로
	for (int i = 0; i < 9; i++) {
		if (s.find(board[i][y]) != s.end())
			s.erase(board[i][y]);
	}
	// 세로
	for (int i = 0; i < 9; i++) {
		if (s.find(board[x][i]) != s.end())
			s.erase(board[x][i]);
	}
}

bool recur(int depth) {
	if (depth == empty_xy.size()) {
		return true;
	}
	set<int> s({1, 2, 3, 4, 5, 6, 7, 8, 9});
	eraseInvalidNum(empty_xy[depth].first, empty_xy[depth].second, s);
	if (s.empty()) // 돌아가야함
		return false;
	for (auto n : s) {
		vector<vector<int> > backup = board;
		board[empty_xy[depth].first][empty_xy[depth].second] = n;
		if (recur(depth + 1)) // 해결!
			return true;
		board = backup;
	}
	return false; // 돌아가야함
}


int main () {
	ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			cin >> board[i][j];
			if (board[i][j] == 0)
				empty_xy.push_back(make_pair(i, j));
		}
	}
	recur(0);
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++)
			cout << board[i][j] << ' ';
		cout << '\n';
	}
}

set 순회, board backup 필요 없이 많이 하는 부분 고쳐서 통과했다.

// 스도쿠
#include <iostream>
#include <vector>

using namespace std;

vector<vector<int> > board(9, vector<int>(9, 0));
vector<pair<int, int> > empty_xy;

// 0 1 2  3 4 5  6 7 8
void eraseInvalidNum(int x, int y, vector<bool>& bv) {
	int start_x = x / 3 * 3, start_y = y / 3 * 3;
	// 3 x 3 박스
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			int n = board[start_x + i][start_y + j];
			bv[n] = false;
		}
	}
	// 가로
	for (int i = 0; i < 9; i++) {
		bv[board[i][y]] = false;
	}
	// 세로
	for (int i = 0; i < 9; i++) {
		bv[board[x][i]] = false;
	}
}

bool recur(int depth) {
	if (depth == empty_xy.size()) {
		return true;
	}
	vector<bool> bv(10, true);
	eraseInvalidNum(empty_xy[depth].first, empty_xy[depth].second, bv);
	for (int i = 1; i < 10; i++) {
		if (bv[i] == false)
			continue;
		board[empty_xy[depth].first][empty_xy[depth].second] = i;
		if (recur(depth + 1)) // 해결!
			return true;
		board[empty_xy[depth].first][empty_xy[depth].second] = 0;
	}
	return false; // 돌아가야함
}

int main () {
	ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			cin >> board[i][j];
			if (board[i][j] == 0)
				empty_xy.push_back(make_pair(i, j));
		}
	}
	recur(0);
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++)
			cout << board[i][j] << ' ';
		cout << '\n';
	}
}

컨테이너 없이 int n 순회하면서 유효한지 검증하는 더 좋은 방법.

#include <iostream>
#include <vector>
#include <set>

using namespace std;

vector<vector<int> > board(9, vector<int>(9, 0));
vector<pair<int, int> > empty_xy;

bool check(int x, int y, int n) {
	for (int i = 0; i < 9; i++) {
		if (board[x][i] == n)
			return false;
		if (board[i][y] == n)
			return false;
	}

	int start_x = x / 3 * 3, start_y = y / 3 * 3;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			if (board[start_x + i][start_y + j] == n)
				return false;
		}
	}
	return true;
}

bool recur(int depth) {
	if (depth == empty_xy.size()) return true;

	for (int n = 1; n <= 9; n++) {
		int x = empty_xy[depth].first;
		int y = empty_xy[depth].second;
		if (check(x, y, n)) {
			board[x][y] = n;
			if (recur(depth + 1))
				return true;
			board[x][y] = 0;
		}
	}
	return false;
}

int main () {
	ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			cin >> board[i][j];
			if (board[i][j] == 0)
				empty_xy.push_back(make_pair(i, j));
		}
	}
	recur(0);
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++)
			cout << board[i][j] << ' ';
		cout << '\n';
	}
}
반응형

'<algorithm> > 백준' 카테고리의 다른 글

백준 14430 자원 캐기 c++  (0) 2023.12.13
백준 2116 주사위 쌓기 c++  (0) 2023.12.12
백준 1025 제곱수 찾기 c++  (0) 2023.11.28
백준 1013 Contact c++  (1) 2023.11.28
백준 12891 DNA 비밀번호 c++  (0) 2023.11.28
profile

그럴듯한 개발 블로그

@donghyk2

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!