POJ3074 Sudoku DFS + 数据优化

  • 题目大意

数独是一种传统益智游戏,你需要把一个9 × 9的数独补充完整,使得图中每行、每列、每个3 × 3的九宫格内数字1~9均恰好出现一次。

请编写一个程序填写数独。
在这里插入图片描述

  • 思路

搜索边界分为两种:
1.是如果所有位置都被填满,就找到了一个解.
2. 如果发现某个位置没有能填的合法数字,说明当前分支搜索失败,应该回溯去尝试其他分支.

由于本题数据比较严格, 不能像POJ2676那样一个一个尝试,所以数据上需要做一些优化。

1.在搜索时, 优先搜索决策少的。
2.每行每列每个九宫格,分别用一个9位二进制数表示,保存还可以选择的数据。
3. 对于每个位置,把它所在行、列、九宫格的3个二进制数做位与(&)运算,就可以得到该位置能填哪些数,用lowbit运算就可以把能填的数字取出。
4. 修改状态.
5. dfs搜索.
6. 回溯.

ones数组: 存每个数中有多少个1, 即是用来存当前这个格子有多少个可选择的决策,找出决策最少的格子然后进行深搜。
map数组: 存某个数子的第一个1的下标, 即是取出这个二进制数的第一个1代表的可以放到格子里面的数字。
代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cstdio>
using namespace std;
const int N = 9;
int row[N], col[N], cell[3][3];
int ones[1 << N], map[1 << N];
char str[100];
int lowbit(int x){
	return x & (-x);
}
void init(){
	for(int i = 0; i < N; i++){
		row[i] = col[i] = (1 << N) - 1;
	}
	for(int i = 0; i < 3; i++){
		for(int j = 0; j < 3; j++) 
			cell[i][j] = (1 << N) - 1;
	}
}
int get(int x, int y){
	return row[x] & col[y] & cell[x / 3][y / 3];
}
bool dfs(int cnt){
	if(!cnt) return true;
	//1找出可选方案数最小的格子
	int maxv = 10;
	int x, y;
	for(int i = 0; i < N; i++)
		for(int j = 0; j < N; j++)
			if(str[i * 9 + j] == '.'){
				int t = ones[get(i, j)];
				if(t <  maxv){
					maxv = t;
					x = i;
					y = j;
				}	
			}
	for(int i = get(x, y); i; i -= lowbit(i)){
		int t = map[lowbit(i)];
		
		//修改状态
		row[x] -= 1 << t;
		col[y] -= 1 << t;
		cell[x / 3][y / 3] -= 1 << t;
		str[x * 9 + y] = '1' + t;
		if(dfs(cnt - 1)) return true;
		//回溯
		row[x] += 1 << t;
		col[y] += 1 << t;
		cell[x / 3][y / 3] += 1 << t;	
		str[x * 9 + y] = '.';	
	}
	return false;
}
int main(){
	for(int i = 0; i < N; i++){
		map[1 << i] = i;
	}
	for(int i = 0; i < 1 << N; i++){
		int s = 0;
		for(int j = i; j ; j -= lowbit(j)) s++;
		ones[i] = s;
	}
	while(cin >> str, str[0] != 'e'){
		init();
		int cnt = 0;
		for(int i = 0, k = 0; i < N; i++){
			for(int j = 0; j < N; j++, k++){
				if(str[k] != '.'){
				int t = str[k] - '1';
				row[i] -= 1 << t;
				col[j] -= 1 << t;
				cell[i / 3][j / 3] -= 1 << t;
				}
				else cnt++;
			}
		}
		dfs(cnt);
		cout << str << endl;
	}
	return 0;
}
发布了54 篇原创文章 · 获赞 155 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_45432665/article/details/104106533