1. 程式人生 > 實用技巧 >POJ 2726、POJ3074 :數獨(二進位制DFS)

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,

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);
	}
}