POJ2676 (数独问题 + DLX + 状态优化顺序)
(1)最简单的最是去暴力DFS搜索答案 , 很容易想到 , 每行每列的方式去搜索 , 不过效率是真的不行;但这个还是给出代码 ,毕竟打了也不容易呀!
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=;
int map[maxn][maxn];
bool row[maxn][maxn];
bool col[maxn][maxn];
bool grid[maxn][maxn];
bool dfs(int r,int c)
{
if(r==) return true;//构造完毕
bool flag=false;
if(map[r][c])
{
if(c==) flag=dfs(r+,);
else flag=dfs(r,c+);
return flag;
}
int k=(r/)*+c/;
for(int i=;i<=;i++)if(!row[r][i]&&!col[c][i]&&!grid[k][i])
{
row[r][i]=col[c][i]=grid[k][i]=true;
map[r][c]=i;
if(c==) flag=dfs(r+,);
else flag=dfs(r,c+);
if(flag) return true;
map[r][c]=;
row[r][i]=col[c][i]=grid[k][i]=false;
}
return false;
}
int main()
{
int T; scanf("%d",&T);
while(T--)
{
memset(row,,sizeof(row));
memset(col,,sizeof(col));
memset(grid,,sizeof(grid));
for(int i=;i<;i++)
for(int j=;j<;j++)
{
char x;
scanf(" %c",&x);
map[i][j]= x-'';
if(map[i][j])
{
row[i][map[i][j]]=true;
col[j][map[i][j]]=true;
int k=(i/)*+j/;
grid[k][map[i][j]]=true;
}
}
dfs(,);
for(int i=;i<;i++)
{
for(int j=;j<;j++)
printf("%d",map[i][j]);
printf("\n");
}
}
return ;
}
(2)还有个更快的 ,就是利用舞蹈链(DLX)这种数据结构去快速实现这种问题 。(DLX:这里先给出模板,不先学习)
//******************************************************//
//输入T表示T组数据。 //
//每组数据为9个长度为9的字符串,空白处以字符0替代。 //
//POJ2676 //
//******************************************************// #include <bits/stdc++.h>
using namespace std;
const int maxnode = ;
const int MaxM = ;
const int MaxN = ;
struct DLX{
int n, m, size; //行数,列数,总数
int U[maxnode], D[maxnode], R[maxnode], L[maxnode], Row[maxnode], Col[maxnode];
int H[MaxN], S[MaxM]; //S记录该列剩余1的个数,H表示该行最左端的1
int ansd, ans[MaxN]; void init(int _n, int _m){
n = _n;
m = _m;
for(int i = ; i <= m; i++){
S[i] = ;
U[i] = D[i] = i;
L[i] = i-;
R[i] = i+;
}
R[m] = ; L[] = m;
size = m;
memset(H, -, sizeof(H));
}
void Link(int r, int c){
size++;
Col[size] = c, Row[size] = r;
S[c]++;
U[size] = U[c], D[size] = c;
D[U[c]] = size;
U[c] = size;
if (H[r] != -) {
R[size] = H[r] ;
L[size] = L[H[r]] ;
R[L[size]] = size ;
L[R[size]] = size ;
}
else
H[r] = L[size] = R[size] = size ;
}
void remove(int c){//覆盖第c列。删除第c列及能覆盖到该列的行,防止重叠
L[R[c]] = L[c]; R[L[c]] = R[c];
for(int i = D[c]; i != c; i = D[i])
for(int j = R[i]; j != i; j = R[j]){
U[D[j]] = U[j];
D[U[j]] = D[j];
--S[Col[j]];
}
}
void resume(int c){
for(int i = U[c]; i != c; i = U[i])
for(int j = L[i]; j != i; j = L[j]){
++ S[Col[j]];
U[D[j]] = j;
D[U[j]] = j;
}
L[R[c]] = R[L[c]] = c;
}
//d为递归深度
bool dance(int d){
if(R[] == ){
ansd = d;
return true;
}
int c = R[];
for(int i = R[]; i != ; i = R[i])
if(S[i] < S[c])
c = i;
remove(c);
for(int i = D[c];i != c;i = D[i]){
ans[d] = Row[i];
for(int j = R[i]; j != i; j = R[j]) remove(Col[j]);
if(dance(d+)) return true;
for(int j = L[i]; j != i; j = L[j]) resume(Col[j]);
}
resume(c);
return false;
}
};
DLX g;
char s[][];
int main(){
int t;
scanf("%d", &t);
while(t--){
for(int i = ; i < ; i++)
scanf("%s", s[i]); g.init(*, +++); for(int i = ; i < ; i++)
for(int j = ; j < ; j++){
int x = i, y = j, z = x/*+y/, w = i*+j;
if(s[i][j] == ''){
for(int k = ; k <= ; k++){
g.Link(w*+k, w+);
g.Link(w*+k, +x*+k);
g.Link(w*+k, +y*+k);
g.Link(w*+k, +z*+k);
}
}
else {
int t = s[i][j]-'';
g.Link(w*+t, w+);
g.Link(w*+t, +x*+t);
g.Link(w*+t, +y*+t);
g.Link(w*+t, +z*+t);
}
}
g.dance(); for(int i = ; i < g.ansd; i++){
int t = g.ans[i];
int a = (t-)/, b = (t-)%+'';
s[a/][a%] = b;
}
for(int i = ; i < ; i++)
puts(s[i]);
}
return ;
}
(3) 还有就是重要需要讲解的状态搜索:
1、答案
状态:我们关心数独每个位置填了什么数。我们需要在每个状态中找出没有填的位置,检查有哪些值可以填。这些可以填的值构成了向下递归的分支。(状态就是每个每个时刻的9*9数独)
搜索边界:1、所有位置填完了,找到答案。2、发现某个位置没有能填的值,搜索失败。
提醒:对于每个状态下,我们要找的是1个位置填什么,而不是枚举所有位置和能填的数(其他位置会在更深的地方被搜索到)。
2、剪枝
优化搜索顺序:如果是人类玩数独,策略一定是先填上“已经能够唯一确定的位置”,考虑在该位置填什么数,再向下搜索。所以我们在每个状态下选择所有未填的位置中,能填合法数字最少的位置,考虑在这上面填数。
3、位运算
对于每行,每列,每个九宫格,分别用一个9为二进制数保存哪些数字还可以填。
对于每个位置,把他锁在的行,列,九宫格对应的数取 & 运算就可以得到剩余哪些数可以填。lowbit(x)取出能填的数。
当某个位置的数填上时把对应的行,列,九宫格对应位置改为0。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std; char str[][];
int row[], col[], grid[], cnt[], num[], tot;
int g(int x, int y){
return ((x / ) * ) + (y / );//在第几个九宫格
}
void flip(int x, int y, int z){
row[x] ^= <<z; //x行z不能填了
col[y] ^= <<z;
grid[g(x,y)] ^= <<z;
} bool dfs(int now){//剩余要填的数的总数
if(now == )return ;
//优化顺序:枚举每个位置,找能填的最少的填
int t = , x, y;
for(int i = ; i < ; i++){
for(int j = ; j < ; j++){
if(str[i][j] != '')continue;
int val = row[i] & col[j] & grid[g(i,j)];
if(!val)return ;
if(cnt[val] < t){///查看那个小宫格填入好
t = 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] = ''+z;
flip(x,y,z);
if(dfs(now-))return ;
flip(x,y,z);
str[x][y] = '';
}
return ;
} int main(){
//每个状态已经填的数有几个
for(int i = ; i < <<; i++)
for(int j = i; j; j-=j&-j)cnt[i]++;
//对于状态(1<<i),对应的数为'1'+num[1<<i];
for(int i = ; i < ; i++)
num[<<i] = i;
int T; cin>>T;
while(T--){
//data in
for(int i = ; i < ; i++)scanf("%s",str[i]);
//初始化,都可以填。
for(int i = ; i < ; i++)row[i] = col[i] = grid[i] = (<<)-;
tot = ;
//
for(int i = ; i < ; i++)
for(int j = ; j < ; j++)
if(str[i][j] != '')flip(i,j,str[i][j]-'');
else tot++;
dfs(tot);
//data out
cout<<'\n';
for(int i = ; i < ; i++)
printf("%s\n",str[i]);
}
return ;
}
POJ2676 (数独问题 + DLX + 状态优化顺序)的更多相关文章
- 任务二:1、选择器 2、连接集中状态的顺序 3、浮动的用发和原理 4、盒模型在IE和Google等不同浏览器的区别与联系
1.选择器类型 标签选择器,类选择器,ID选择器,组合选择器,伪类和伪元素,属性选择器,子选择器,同胞选择器, :not()选择器 1.同胞选择器 相邻同胞标签: h2 + p{ color:red; ...
- Oracle性能优化顺序表名称来选择最有效的学习笔记
选择最有效的顺序表名(只有有效的基于规则的优化) ORACLE分析器按照订单处理从右到左FROM在FROM子句中的表名,故FROM写在最后的表(基础表 driving table)将被最先处理. 在 ...
- NOIP 2009 靶形数独(DLX)
小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向Z 博士请教,Z 博士拿出了他最近发明的“靶形数独”,作 ...
- [NOIP2009]靶形数独 深搜+枝杈优化
这道题,又是一位玄学搜索...... 我是用的蜗牛序搜的(顾名思义,@,这么搜),我正着搜80然后一反转比原来快了几十倍........一下AC....... 我的思路是这样的话我们可以从内到外或者从 ...
- CSS链接四种状态注意顺序、UI伪类选择器的顺序
css定义超链接是要有先后顺序的.否则,可能会出现某个或某几个样式不起作用的bug.例如:visited与hover顺序颠倒了,则不能显示hover和active的样式了. 正确的顺序: a:link ...
- [C1] C1ComboBox 的非编辑状态优化
一.前言 先看看 WPF 自带的 ComboBox 在非编辑状态,自定义 ItemTemplate 的情况下,效果如下图所示: 其当前选中的项(红框内)与自定义的 ItemTemplate 一样: 但 ...
- 根据 MySQL 状态优化 ---- 4. 临时表
查看 MySQL 服务器运行的各种状态值: mysql> show global status: 4. 临时表 查看设置: mysql> show variables where Vari ...
- 根据 MySQL 状态优化 ---- 1. 慢查询
查看 MySQL 服务器运行的各种状态值: mysql> show global status: 1. 慢查询 mysql> show variables like '%slow%'; + ...
- Mysql 【影响性能的几个方面】以及【性能优化顺序】
服务器性能 cpu 可用内存大小 网络 IO (增加IO子系统) mysql 存储引擎 数据库服务器配置参数(主要优化方向) 数据库结构设计,sql语句. 慢查询
随机推荐
- char 与 String 之间的转换
public class Test { public static void main(String [] args) { char c = 'a'; System.out.println (c); ...
- ssh框架搭建实例代码教程步骤
http://blog.csdn.net/u010539352/article/details/49255729
- [CSS Hack]解決IE6、IE7、IE8、Firefox的瀏覽器相容性問題!
每次調CSS最令人頭痛的就是瀏覽器校正問題,因為每個瀏覽器對CSS的解釋都不太一樣,Firefox本身算是比較照規矩來,處理上比較簡單,但是遇到微軟的IE系列頭就大了,雖然都是IE,但是IE6.IE7 ...
- java多线程环境单例模式实现详解
Abstract 在开发中,如果某个实例的创建需要消耗很多系统资源,那么我们通常会使用惰性加载机制,也就是说只有当使用到这个实例的时候才会创建这个实例,这个好处在单例模式中得到了广泛应用.这个机制在s ...
- C++面向对象类的实例题目九
题目描述: 编写一个学生和老师数据输入和显示程序,学生数据有编号.姓名.班号和成绩,教师数据有编号.姓名.职称和部门. 要求将编号.姓名.输入和显示设计成一个类person,并作为学生数据操作类stu ...
- SqlServer中把结果集放到到临时表的方法(转)
一. SELECT INTO 1. 使用select into会自动生成临时表,不需要事先创建 select * into #temp from sysobjects 01. 把存储过程结 ...
- session跨域共享
www.maxomnis.com的index.php文件内容 <?phpsession_start();setcookie("user", "alex proter ...
- 3dsmax里面的喷射器spray和超级喷射器superspray是个什么东西
以前搜索过粒子系统的一些资料,最早有一篇什么论文里提到一种方法可以用计算机模拟一些看起来数目比较多的一些效果,比如 很多雨滴.下雪天的雪花,作者把这个东西叫particle system,就是粒子系统 ...
- 算法Sedgewick第四版-第1章基础-022一QueueWithTwoStacks
/****************************************************************************** * Compilation: javac ...
- 前端基础 之JS
浏览目录 JavaScript语法基础 JavaScript数据类型及类型查询 JavaScript运算符 JavaScript流程控制 JavaScript函数 词法分析 JavaScript内置对 ...