POJ2676,HDU4069解决数独的两种实现:DFS、DLX
搜索实现:解决数独有两种思考策略,一种是枚举当前格能填的数字的种数,这里有一优化策略就是先搜索能填入种数小的格子;另一种是考虑处理某一行(列、宫)时,对于某一个没用过的数字,若该行(列、宫)只有一个可行的空白格时,就只能将该数字填入此格中。第二种实现起来略麻烦,此处仅实现第一种策略,并调整搜索顺序进行优化操作,优先搜索能填数字种数较小的格子。
另外,在搜索时,条件判断的效率尤为重要,故分别记录各行、各列、各宫已经出现的数字,这样就可以直接判断该空格填入某数字是否可行。
以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的更多相关文章
- 分布式理论基础(一)一致性及解决一致性的两种方式:2PC和3PC (转载 不错)
分布式理论基础(一)一致性及解决一致性的两种方式:2PC和3PC 1 一致性 1.1 简述 一致性,是指对每个节点一个数据的更新,整个集群都知道更新,并且是一致的 假设一个具有N个节点的分布式系统,当 ...
- Android Studio无法预览xml布局之解决方法(两种)
学习安卓程序开发,用的Android Studio,发现怎么更改xml代码都没有想要的效果.如图 代码如下: <?xml version="1.0" encoding=&qu ...
- TortoiseGit 解决冲突的两种方法
一.冲突发生原因: 用户A 有新提交 用户B 没有pull, 写新代码 ,pull , 提示有冲突 Solution: 1: stash save(把自己的代码隐藏存起来) -> 重新pul ...
- C#实体对象序列化成Json并让字段的首字母小写的两种解决方法
引言:最近在工作中遇到与某些API对接的post的数据需要将对象的字段首字母小写.解决办法有两种:第一种:使用对象的字段属性设置JsonProperty来实现(不推荐,因为需要手动的修改每个字段的属性 ...
- CSS中清除浮动的两种方式
在CSS中,父元素中的子元素如果使用了float,会导致父元素塌陷,高度为0. 对于这种情况,常见的解决方式有两种. 一.增加新的div,应用clear:both属性 html: <div cl ...
- ajax乱码问题 服务端 客户端 两种的解决方案--转载
今天弄了一天的Ajax中文乱码问题,Ajax的乱码问题分为两种: 1. JavaScript输出的中文乱码, 比如:alert("中文乱码测试"); 2. 这第二种就是Ajax从服 ...
- Struts 2 数据校验要用到的类和两种校验方式以及一些校验问题的解决
通过继承ActionSupport类来完成Action开发,ActionSupport类不仅对Action接口进行简单实现, 同时增加了验证.本地化等支持 .真实开发中自定义Action都需要继承该类 ...
- Ajax跨域问题的两种解决方法
浏览器不允许Ajax跨站请求,所以存在Ajax跨域问题,目前主要有两种办法解决. 1.在请求页面上使用Access-Control-Allow-Origin标头. 使用如下标头可以接受全部网站请求: ...
- WebGIS中解决使用Lucene进行兴趣点搜索排序的两种思路
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 目前跟信息采集相关的一个项目提出了这样的一个需求:中国银行等 ...
随机推荐
- MySQL数据库的常用操作
/*创建表*/ CREATE TABLE tb_test ( id ) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', name ) NOT NULL ...
- Python字符界面函数库
curses ncurses prettytable from prettytable import PrettyTable row = PrettyTable() row.field_names = ...
- HDU 1024:Max Sum Plus Plus(DP)
http://acm.hdu.edu.cn/showproblem.php?pid=1024 Max Sum Plus Plus Problem Description Now I think you ...
- Cocos2dx-lua开发之c++绑定到lua
一. 简单介绍 文章介绍是在实际的游戏开发项目中,将自定义的C++类绑定到lua中,能够让lua调用c++类.会创建一个python脚本,执行python脚本会让自动将我们的c++类绑定到lua.生成 ...
- Integer Inquiry -TJU1112
作为最简单的高精度加法,要注意的是如下几点, 第一,因为是数位达到上百位的大数,所以只能用字符串数组来存贮. 第二,为了方便之后的相加操作,应该把字符串数组逆序转化为一个整型数组. 第三,在控制进位的 ...
- hasOwnproperty详细总结
hasOwnProperty:是用来判断一个对象是否有你给出名称的属性或对象.不过需要注意的是,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员. isPrototypeO ...
- Pots 分类: 搜索 POJ 2015-08-09 18:38 3人阅读 评论(0) 收藏
Pots Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11885 Accepted: 5025 Special Judge D ...
- 基于@AspectJ和schema的aop(一)
在前面我们使用Pointcut和Advice描述切点和增强, 并使用Advisor整合两者描述切面.@AspectJ使用注解来描述切点和增强.两者使用的方式不同, 但是在本质上都是一样的. 我们还是用 ...
- SharePoint自动化系列——Manage "Site Subscriptions" using PowerShell
转载请注明出自天外归云的博客园:http://www.cnblogs.com/LanTianYou/ 你可以将普通的sites加入到你的site subscriptions中,前提是你需要有一个 Te ...
- #ifdef _DEBUG
#ifdef _DEBUG virtual void AssertValid() const; //assert(断言)valid(有效的,正确的) virtual void Dump(CDumpCo ...