搜索实现:解决数独有两种思考策略,一种是枚举当前格能填的数字的种数,这里有一优化策略就是先搜索能填入种数小的格子;另一种是考虑处理某一行(列、宫)时,对于某一个没用过的数字,若该行(列、宫)只有一个可行的空白格时,就只能将该数字填入此格中。第二种实现起来略麻烦,此处仅实现第一种策略,并调整搜索顺序进行优化操作,优先搜索能填数字种数较小的格子。

另外,在搜索时,条件判断的效率尤为重要,故分别记录各行、各列、各宫已经出现的数字,这样就可以直接判断该空格填入某数字是否可行。

以POJ2676为例,无调整搜索顺序的优化,用时26ms,调整搜索顺序后用时0ms。

 //dfs搜索,枚举当前格能填的数字
#include <stdio.h>
#include <algorithm>
using namespace std;
const int N = ;
char mp[N+][N+];
int row[N+], col[N+], squ[N+];
struct p{
int x, y, z;
p(int a = , int b = , int c = ) :x(a), y(b), z(c){}
bool operator <(const p& m)const {
return z < m.z;
}
};
p pa[N*N+];
int tot; bool dfs(int d) {
if (d == tot) return true; for(int i = d; i < tot; i++){
int nn = , x = pa[i].x, y = pa[i].y;
pa[i].z = ;
for(int j = ; j < ; j <<= )
if( !(row[x]&j) && !(col[y]&j) && !(squ[x/*+y/]&j) )
pa[i].z++;
}
sort(pa+d, pa+tot);//调整搜素顺序!! int x = pa[d].x, y = pa[d].y;
for(int i = ; i <= N; i++){
int j = <<(i-);
if(!(row[x]&j) && !(col[y]&j) && !(squ[x/*+y/]&j)){
row[x] ^= j, col[y] ^= j, squ[x/*+y/] ^= j;
mp[x][y] = ''+i;
if(dfs(d+)) return true;
row[x] ^= j, col[y] ^= j, squ[x/*+y/] ^= j;
}
}
return false;
} int main(){
int t; scanf("%d", &t);
while(t--){
for(int i = ; i < ; i++)
for(int j = ; j < ; j++)
scanf(" %c", &mp[i][j]); for(int i = ; i < N; i++)
row[i] = col[i] = squ[i] = ;
tot = ; for(int i = ; i < N; i++)
for(int j = ; j < N; j++)
if(mp[i][j] != ''){
int idx = mp[i][j]-'';
row[i] |= <<idx, col[j] |= <<idx, squ[i/*+j/] |= <<idx;
}
else
pa[tot++] = p(i, j); for(int i = ; i < tot; i++){
int nn = , x = pa[i].x, y = pa[i].y;
for(int j = ; j < ; j <<= )
if( !(row[x]&j) && !(col[y]&j) && !(squ[x/*+y/]&j) )
pa[i].z++;
} dfs(); for (int i = ; i < ; ++i)
puts(mp[i]);
}
return ;
}

DLX算法的POJ2676

 //******************************************************//
//输入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 ;
}

DLX算法很容易,套个框架就能解决了,还能高效解决变形数独。用HDU4069,一个变形数独为例。

 //******************************************************//
//hdu4069 //
//******************************************************//
#include <bits/stdc++.h>
using namespace std;
const int MaxM = +;
const int MaxN = +;
const int maxnode = MaxM*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];
int temp[MaxN];
int tot; 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)); tot = ;
}
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为递归深度
int dance(int d){
if(R[] == ){
ansd = d;
for(int i = ; i < ansd; i++)
ans[i] = temp[i];
tot++;
return tot;
}
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]){
temp[d] = Row[i];
for(int j = R[i]; j != i; j = R[j]) remove(Col[j]);
if(dance(d+) > ) return tot;
for(int j = L[i]; j != i; j = L[j]) resume(Col[j]);
}
resume(c);
return tot;
}
};
DLX g; int a[][];
int gird[][];
int d[][] = {{-,},{,},{,},{,-}};//u,r,d,l
void dfs(int x, int y, int color){
gird[x][y] = color;
for(int i = ; i < ; i++){
int xx = x+d[i][], yy = y+d[i][];
if((a[x][y] & (<<i))== &&xx >= && xx < &&yy >= &&yy <&&gird[xx][yy] == -)
dfs(xx, yy, color);
}
return ;
} int main(){
int T; scanf("%d", &T);
for(int ca = ; ca <= T; ca++){
for(int i = ; i < ; i++)
for(int j = ; j < ; j++)
scanf("%d", &a[i][j]);
memset(gird, -, sizeof(gird));
int tt = ;
for(int i = ; i < ; i++)
for(int j = ; j < ; j++)
if(gird[i][j] == -) dfs(i, j, tt++); g.init(*, *);
for(int i = ; i < ; i++)
for(int j = ; j < ; j++){
int t = (a[i][j]&), w = i*+j, x = i, y = j, z = gird[i][j];
if(t){
g.Link(w*+t, w+);
g.Link(w*+t, +x*+t);
g.Link(w*+t, +y*+t);
g.Link(w*+t, +z*+t);
}else {
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);
}
}
} printf("Case %d:\n", ca);
int ret = g.dance();
if(ret == ){
for(int i = ; i < g.ansd; i++){
int t = g.ans[i];
int x = (t-)/, y = (t-)%+;
a[x/][x%] = y;
}
for(int i = ; i < ; i++){
for(int j = ; j < ; j++)
printf("%d", a[i][j]);
puts("");
}
}
else if(ret > ) puts("Multiple Solutions");
else puts("No solution");
}
return ;
}

POJ2676,HDU4069解决数独的两种实现:DFS、DLX的更多相关文章

  1. 分布式理论基础(一)一致性及解决一致性的两种方式:2PC和3PC (转载 不错)

    分布式理论基础(一)一致性及解决一致性的两种方式:2PC和3PC 1 一致性 1.1 简述 一致性,是指对每个节点一个数据的更新,整个集群都知道更新,并且是一致的 假设一个具有N个节点的分布式系统,当 ...

  2. Android Studio无法预览xml布局之解决方法(两种)

    学习安卓程序开发,用的Android Studio,发现怎么更改xml代码都没有想要的效果.如图 代码如下: <?xml version="1.0" encoding=&qu ...

  3. TortoiseGit 解决冲突的两种方法

    一.冲突发生原因: 用户A 有新提交 用户B 没有pull, 写新代码 ,pull , 提示有冲突   Solution: 1: stash save(把自己的代码隐藏存起来) -> 重新pul ...

  4. C#实体对象序列化成Json并让字段的首字母小写的两种解决方法

    引言:最近在工作中遇到与某些API对接的post的数据需要将对象的字段首字母小写.解决办法有两种:第一种:使用对象的字段属性设置JsonProperty来实现(不推荐,因为需要手动的修改每个字段的属性 ...

  5. CSS中清除浮动的两种方式

    在CSS中,父元素中的子元素如果使用了float,会导致父元素塌陷,高度为0. 对于这种情况,常见的解决方式有两种. 一.增加新的div,应用clear:both属性 html: <div cl ...

  6. ajax乱码问题 服务端 客户端 两种的解决方案--转载

    今天弄了一天的Ajax中文乱码问题,Ajax的乱码问题分为两种: 1. JavaScript输出的中文乱码, 比如:alert("中文乱码测试"); 2. 这第二种就是Ajax从服 ...

  7. Struts 2 数据校验要用到的类和两种校验方式以及一些校验问题的解决

    通过继承ActionSupport类来完成Action开发,ActionSupport类不仅对Action接口进行简单实现, 同时增加了验证.本地化等支持 .真实开发中自定义Action都需要继承该类 ...

  8. Ajax跨域问题的两种解决方法

    浏览器不允许Ajax跨站请求,所以存在Ajax跨域问题,目前主要有两种办法解决. 1.在请求页面上使用Access-Control-Allow-Origin标头. 使用如下标头可以接受全部网站请求: ...

  9. WebGIS中解决使用Lucene进行兴趣点搜索排序的两种思路

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 目前跟信息采集相关的一个项目提出了这样的一个需求:中国银行等 ...

随机推荐

  1. 事务的隔离级别及mysql对应操作

    /* 本次高并发解决之道 1,更改事务隔离级别为 read uncommitted读未提交 2,查询前设定延迟,延迟时间为随机 50-500 微秒 3,修改数据前将 超范围作为 限定修改条件 事务是作 ...

  2. yii2 批量插入or更新

    $sql1 = 'insert into business_ip (gid, name, area, belongName, belongArea, destIPv4, created, update ...

  3. ACM题目————星际之门(一)

    描述 公元3000年,子虚帝国统领着N个星系,原先它们是靠近光束飞船来进行旅行的,近来,X博士发明了星际之门,它利用虫洞技术,一条虫洞可以连通任意的两个星系,使人们不必再待待便可立刻到达目的地. 帝国 ...

  4. 两句话概括“sql外键”

    外键的使用就是: 1.外键表可以删除,外键表删完了 才能删主键表2.添加的时候不能添加在主键没有的内容

  5. EFsql笔记

    like的语法 string[] cities = { "London", "Madrid" }; IQueryable<Customer> cus ...

  6. 在IE6下使用filter设置png背景

    今天帮别人解决问题学会了一个在IE6下使用filter设置png背景,具体css写法如下: .login_form_wrap { width: 778px; height: 360px; backgr ...

  7. 【20160924】GOCVHelper 图像增强部分(4)

    //使得rect区域半透明     Mat translucence(Mat src,Rect rect,int idepth){         Mat dst = src.clone();     ...

  8. 2016年11月28日 星期一 --出埃及记 Exodus 20:19

    2016年11月28日 星期一 --出埃及记 Exodus 20:19 and said to Moses, "Speak to us yourself and we will listen ...

  9. jar文件签名

    1.生成密钥: keytool -genkey -keystore key.keystore -alias key -validity 3650 将在当前目录下生成一个key.keystore文件, ...

  10. sql 流水号

    CREATE TABLE [dbo].[SriaNum] ( [Num] [int] NOT NULL) alter PROC dpIDS_GetSerialNumber@SerialNumber V ...