解数独。

分析

考虑如何把数独解合法的条件转化为经典的01精确覆盖:

  • 每个格子只能填一个数,1-9
  • 每一列刚好填了1-9
  • 每一行刚好填了1-9
  • 每个九宫格刚好填了1-9

也就是说,每个格子,列,行,九宫格都需要被一个数覆盖,且不能重复覆盖。

精确覆盖的一个很巧妙的,也很常用的建矩阵方法,是把条件拆开,把每一个填入也拆成对四种条件的贡献。

也就是说,我们建一个729*324的矩阵。所有的行表示在\((x,y)\)填入\(k\),前81列表示每个格子被覆盖,后面的各81列分别表示每一列,一行,九宫格被覆盖,那么这就是一个精确覆盖问题了——每次填入一个数,可以对应地在四个规则中产生贡献。

如果已经给到有数了,那么就\((x,y)\)就只能填入规定的那个\(k\),否则可以填1-9。

代码

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=10*10*10;
const int maxm=10*10*5;
const int maxl=10*10;
const int maxp=maxn*maxm;
bool a[maxn][maxm];
char s[maxl];
int ans[10][10];
struct node {
int l,r,u,d,row,col;
};
int id(int x,int y) {
return (x-1)*9+y;
}
int hang(int x,int k) {
return 81+(x-1)*9+k;
}
int lie(int y,int k) {
return 162+(y-1)*9+k;
}
int bel(int x,int y) {
return ((x-1)/3)*3+(y-1)/3+1;
}
int gong(int x,int y,int k) {
return 243+(bel(x,y)-1)*9+k;
}
int choose(int x,int y,int k) {
return (id(x,y)-1)*9+k;
}
void ANS(int row) {
int k=(row-1)%9+1;
row-=k;
int d=row/9+1;
int y=(d-1)%9+1;
int x=(d-y)/9+1;
ans[x][y]=k;
}
struct DLX {
node p[maxp];
int tot,last[maxm],size[maxm];
void clear(int n) {
tot=n;
memset(p,0,sizeof p),memset(last,0,sizeof last),memset(size,0,sizeof size);
p[0]=(node){n,1,0,0,0,0};
for (int i=1;i<=n;++i) p[i]=(node){i-1,i+1,i,i,0,i},last[i]=i;
p[n].r=0;
}
void build(int row,int c[],int len) {
if (!len) return;
p[++tot]=(node){tot,tot,last[c[1]],p[last[c[1]]].d,row,c[1]};
p[p[tot].u].d=p[p[tot].d].u=last[c[1]]=tot;
++size[p[tot].col];
for (int i=2;i<=len;++i) {
int x=c[i];
p[++tot]=(node){tot-1,p[tot-1].r,last[x],p[last[x]].d,row,x};
p[p[tot].l].r=p[p[tot].r].l=p[p[tot].d].u=p[p[tot].u].d=last[x]=tot;
++size[p[tot].col];
}
}
void del(int c) {
p[p[c].l].r=p[c].r,p[p[c].r].l=p[c].l;
for (int i=p[c].d;i!=c;i=p[i].d)
for (int j=p[i].r;j!=i;j=p[j].r)
p[p[j].u].d=p[j].d,p[p[j].d].u=p[j].u,--size[p[j].col];
}
void back(int c) {
p[p[c].l].r=p[p[c].r].l=c;
for (int i=p[c].u;i!=c;i=p[i].u)
for (int j=p[i].l;j!=i;j=p[j].l)
p[p[j].u].d=p[p[j].d].u=j,++size[p[j].col];
}
bool dance() {
if (!p[0].r) return true;
int first=p[0].r;
for (int i=p[0].r;i;i=p[i].r) if (size[i]<size[first]) first=i;
if (p[first].d==first) return false;
del(first);
for (int i=p[first].d;i!=first;i=p[i].d) {
for (int j=p[i].r;j!=i;j=p[j].r) del(p[j].col);
ANS(p[i].row);
if (dance()) return true;
for (int j=p[i].l;j!=i;j=p[j].l) back(p[j].col);
}
back(first);
return false;
}
} dlx;
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
while (~scanf("%s",s+1)) {
dlx.clear(324);
memset(a,0,sizeof a),memset(ans,0,sizeof ans);
if (s[1]=='e') break;
for (int i=1,k=0;i<=9;++i) for (int j=1;j<=9;++j) {
int x=(s[++k]=='.'?0:s[k]-'0'),st=(x?x:1),ed=(x?x:9);
ans[i][j]=x;
for (int k=st;k<=ed;++k) {
int cho=choose(i,j,k);
a[cho][id(i,j)]=a[cho][hang(i,k)]=a[cho][lie(j,k)]=a[cho][gong(i,j,k)]=true;
}
}
for (int i=1;i<=729;++i) {
static int c[maxm];
int tot=0;
for (int j=1;j<=324;++j) if (a[i][j]) c[++tot]=j;
dlx.build(i,c,tot);
}
dlx.dance();
for (int i=1;i<=9;++i) for (int j=1;j<=9;++j) printf("%d",ans[i][j]);
puts("");
}
return 0;
}

poj3074-Sodoku的更多相关文章

  1. POJ3074 Sudoku

    POJ3074 Sudoku 与POJ2676相比,这一题搜索时每一步都找到最好确定的点进行枚举 对于每行.每列.每个九宫格,都分别用一个9位二进制数保存还有那些数还可以填 对于每个位置,将其所在行. ...

  2. POJ3074 Sudoku 舞蹈链 DLX

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目(传送门) 题意概括 给出一个残缺的数独,求解. 题解 DLX + 矩阵构建  (两个传送门) 代码 #include & ...

  3. poj3074 DLX精确覆盖

    题意:解数独 分析: 完整的数独有四个充要条件: 1.每个格子都有填数字 2.每列都有1~9中的每个数字 3.每行都有1~9中的每个数字 4.每个9宫格都有1~9中的每个数字 可以转化成精确覆盖问题. ...

  4. POJ3074 Sudoku(lowbit优化搜索)

    In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For exa ...

  5. POJ3074 Sudoku 剪枝深(神?)搜

    emm...挺秀的...挺神的? 每行,每列,每宫用一个二进制数表示选或没选的状态,刚开始设没选为1,然后更改状态的时候异或一下就好了: 这样可以通过lowbit取出每一个没有选过的数:(妙啊? 关于 ...

  6. POJ3074 Sudoku —— Dancing Links 精确覆盖

    题目链接:http://poj.org/problem?id=3074 Sudoku Time Limit: 1000MS   Memory Limit: 65536K Total Submissio ...

  7. 数独(深搜)(poj2726,poj3074)

    数独(深搜)数据最弱版本(poj 2676) Description Sudoku is a very simple task. A square table with 9 rows and 9 co ...

  8. 【POJ3074】Sudoku DLX(Dancing Links)

    数独就要DLX,不然不乐意. 数独的DLX构造:9*9个点每一个点有9种选择,这构成了DLX的729行,每行.列.阵有限制,均为9行(/列/阵),然后每行(/列/阵)都有九种数的情况.于是就有了3*9 ...

  9. [poj3074]Sudoku(舞蹈链)

    题目链接:http://poj.org/problem?id=3074 舞蹈链精确覆盖的经典题目,一个数独每个位置的要求,可以得到以下四个约束1.每个位置有且只有一个数字2.每个位置的数字在一行只能出 ...

  10. 【Dancing Link专题】解题报告

    DLX用于优化精确覆盖问题,由于普通的DFS暴力搜索会超时,DLX是一个很强有力的优化手段,其实DLX的原理很简单,就是利用十字链表的快速删除和恢复特点,在DFS时删除一些行和列以减小查找规模,使得搜 ...

随机推荐

  1. Java基础—IO小结(二)缓冲流与其它流的使用

    一.缓冲流的使用 每个字节流都有对应的缓冲流: BufferedInputStream / BufferedOutputStream 构造器: 方法摘要与对应节点流类似 使用缓冲流实现文件复制:实际中 ...

  2. mysql题目练习的答案

    rianley 博客 盗版必究!基于上一个sql练习的答案:该答案是我所写!如果有错误或者用法不当之处:请下方评论指出:感激不尽!谢谢各位码友! <!--1.查询所有的课程的名称以及对应的任课老 ...

  3. OpenCV 3.2 Tracking 物体跟踪

    跟踪就是在连续视频帧中定位物体,通常的跟踪算法包括以下几类: 1. Dense Optical Flow 稠密光流 2. Sparse Optical Flow 稀疏光流 最典型的如KLT算法(Kan ...

  4. CentOS 7.2安装11g数据库软件

      Preface       Yesterday I've installed the 11g GI software on CentOS 7.2.But I still encounter som ...

  5. (原) MaterialEditor部- UmateriaEditor中 Node编译过程和使用(1)

    @author: 白袍小道 转载说明原处 插件同步在GITHUB: DaoZhang_XDZ     最后YY需求(手滑) 1.在理清楚基础套路和细节后,自定义纹理资源,并加入到现有UE材质系统 2. ...

  6. synchronized 详细解说

    转自  http://blog.csdn.net/javazejian/article/details/72828483 出自[zejian的博客] 写的很详细很好,做下记录 本篇主要是对Java并发 ...

  7. python3对接聊天机器人API

    详情见http://api.qingyunke.com/智能机器人API接口说明支持功能:天气.翻译.藏头诗.笑话.歌词.计算.域名信息/备案/收录查询.IP查询.手机号码归属.人工智能聊天接口地址: ...

  8. java学习笔记-9.违例差错控制

      1.违例规范是告诉程序员这个方法可能抛出哪些类型的异常.他的格式在方法声明中,位于自变量(参数)列表的后面,如void f() throws tooBig, tooSmall, divZero { ...

  9. python常用命令—终端安装win32的两种方法

    1, pip install pywin32 2, pip install pypiwin32

  10. 开源自动驾驶仿真平台 AirSim (3) - 运行 AirSim

    AirSim 的官方 Github: https://github.com/Microsoft/AirSim 之前配置了很多,终于要让 AirSim 自己跑起来了. 我们需要把 AirSim 这个插件 ...