POJ 2726、POJ3074 :数独(二进制DFS)

题目链接:https://ac.nowcoder.com/acm/contest/1014/B

题目描述

In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example,

img

Given some of the numbers in the grid, your goal is to determine the remaining numbers such that the numbers 1 through 9 appear exactly once in (1) each of nine 3 × 3 subgrids, (2) each of the nine rows, and (3) each of the nine columns.

输入描述:

The input test file will contain multiple cases. Each test case consists of a single line containing 81 characters, which represent the 81 squares of the Sudoku grid, given one row at a time. Each character is either a digit (from 1 to 9) or a period (used to indicate an unfilled square). You may assume that each puzzle in the input will have exactly one solution. The end-of-file is denoted by a single line containing the word “end”.

输出描述:

For each test case, print a line representing the completed Sudoku puzzle.

示例1

输入

.2738..1..1...6735.......293.5692.8...........6.1745.364.......9518...7..8..6534.
......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.
end

输出

527389416819426735436751829375692184194538267268174593643217958951843672782965341
416837529982465371735129468571298643293746185864351297647913852359682714128574936

分析

  • 可以从左上角一行一行扫描到右下角,对于每一个块列举每一种可能,然后从每个可能出发继续深度遍历直到发现有一个块没有数字可以填时停止
  • 如何储存每一块可以填写的数字?可以利用九位二进制数来表示每一行,每一列,每个九宫格的数字填写情况,然后直接对这三个数字做按位与运算就可以得到某一具体块可以填的数字了。
  • 这里直接用bitset,对于每一个结果,直接遍历一下就可以了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char str[10][10];
int row[9], col[9], grid[9], cnt[512], num[512], tot;

inline int g(int x, int y) {
	return ((x / 3) * 3) + (y / 3);
}

inline void flip(int x, int y, int z) {
	row[x] ^= 1 << z;
	col[y] ^= 1 << z;
	grid[g(x, y)] ^= 1 << z;
}

bool dfs(int now) {
	if (now == 0) return 1;
	int temp = 10, x, y;
	for (int i = 0; i < 9; i++)
		for (int j = 0; j < 9; j++) {
			if (str[i][j] != '.') continue;
			int val = row[i] & col[j] & grid[g(i, j)];
			if (!val) return 0;
			if (cnt[val] < temp) {
				temp = cnt[val];
				x = i, y = j;
			}
		}
	int val = row[x] & col[y] & grid[g(x, y)];
	for (; val; val -= val&-val) {
		int z = num[val&-val];
		str[x][y] = '1' + z;
		flip(x, y, z);
		if (dfs(now - 1)) return 1;
		flip(x, y, z);
		str[x][y] = '.';
	}
	return 0;
}

int main() {
	for (int i = 0; i < 1 << 9; i++)
		for (int j = i; j; j -= j&-j) cnt[i]++;
	for (int i = 0; i < 9; i++)
		num[1 << i] = i;
	char s[100];
	while (~scanf("%s", s) && s[0] != 'e') {
		for (int i = 0; i < 9; i++)
			for (int j = 0; j < 9; j++) str[i][j] = s[i * 9 + j];
		for (int i = 0; i < 9; i++) row[i] = col[i] = grid[i] = (1 << 9) - 1;
		tot = 0;
		for (int i = 0; i < 9; i++)
			for (int j = 0; j < 9; j++)
				if (str[i][j] != '.') flip(i, j, str[i][j] - '1');
				else tot++;
		dfs(tot);
		for (int i = 0; i < 9; i++)
			for (int j = 0; j < 9; j++) s[i * 9 + j] = str[i][j];
		puts(s);
	}
}
posted @ 2020-08-10 14:13  RioTian  阅读(242)  评论(3编辑  收藏  举报