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.背景 目前跟信息采集相关的一个项目提出了这样的一个需求:中国银行等 ...
随机推荐
- ACM题目————一笔画问题
描述 zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,判断一个图是否能够用一笔画下来. 规定,所有的边都只能画一次,不能重复画. 输入 第一行只有一个正整数N(N< ...
- c#之线程
//Process[] pro= Process.GetProcesses(); //foreach (var item in pro) //{ // Console.WriteLine(item); ...
- ural 1110,快速幂
题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1110 题意: X^N % M = Y,X=[0,M-1];没有输出-1: #incl ...
- SSH配置私钥登陆服务器
前言 本文基于实际Linux管理工作,实例讲解工作中使用ssh证书登录的实际流程,讲解ssh证书登录的配置原理,基于配置原理,解决实际工作中,windows下使用SecureCRT证书登录的各种问题, ...
- sql 流水号
CREATE TABLE [dbo].[SriaNum] ( [Num] [int] NOT NULL) alter PROC dpIDS_GetSerialNumber@SerialNumber V ...
- 【Java】常见的Set类型,HashSet、TreeSet、LinkedHashSet
HashSet,锋芒毕露,我们最常用到.其他两个,我们较少用到,今天,我们看看他们的区别. import java.util.HashSet; import java.util.Set; public ...
- CSocket服务器(TCP)
我的理解:把服务器和客户端的交互工程比喻成外来人员访问公司,每来一个客户端访问,需要服务器的前台经理接待此客户,然后前台经理呼叫一个接待员来将客户带上楼.服务器的两个角色前台经理和接待员就是服务器的两 ...
- XMPP Server
XMPPFramework,编译失败,@import libxmlSimu后提示:Module 'libxmlSimu' not found XMPP协议实现原理介绍 XMPP协议学习笔记 四.地址格 ...
- wamp出现could not execute run action问题
wamp出现could not execute run action问题 原文地址:http://blog.sina.com.cn/s/blog_4a60ba9c0100zzlr.html上午 ...
- linux下导入、导出mysql数据库命令
一.导出数据库用mysqldump命令(注意mysql的安装路径,即此命令的路径): 1.导出数据和表结构: mysqldump -u用户名 -p密码 数据库名 > 数据库名.sql #/usr ...