poj3074-Sodoku
解数独。
分析
考虑如何把数独解合法的条件转化为经典的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的更多相关文章
- POJ3074 Sudoku
POJ3074 Sudoku 与POJ2676相比,这一题搜索时每一步都找到最好确定的点进行枚举 对于每行.每列.每个九宫格,都分别用一个9位二进制数保存还有那些数还可以填 对于每个位置,将其所在行. ...
- POJ3074 Sudoku 舞蹈链 DLX
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目(传送门) 题意概括 给出一个残缺的数独,求解. 题解 DLX + 矩阵构建 (两个传送门) 代码 #include & ...
- poj3074 DLX精确覆盖
题意:解数独 分析: 完整的数独有四个充要条件: 1.每个格子都有填数字 2.每列都有1~9中的每个数字 3.每行都有1~9中的每个数字 4.每个9宫格都有1~9中的每个数字 可以转化成精确覆盖问题. ...
- POJ3074 Sudoku(lowbit优化搜索)
In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For exa ...
- POJ3074 Sudoku 剪枝深(神?)搜
emm...挺秀的...挺神的? 每行,每列,每宫用一个二进制数表示选或没选的状态,刚开始设没选为1,然后更改状态的时候异或一下就好了: 这样可以通过lowbit取出每一个没有选过的数:(妙啊? 关于 ...
- POJ3074 Sudoku —— Dancing Links 精确覆盖
题目链接:http://poj.org/problem?id=3074 Sudoku Time Limit: 1000MS Memory Limit: 65536K Total Submissio ...
- 数独(深搜)(poj2726,poj3074)
数独(深搜)数据最弱版本(poj 2676) Description Sudoku is a very simple task. A square table with 9 rows and 9 co ...
- 【POJ3074】Sudoku DLX(Dancing Links)
数独就要DLX,不然不乐意. 数独的DLX构造:9*9个点每一个点有9种选择,这构成了DLX的729行,每行.列.阵有限制,均为9行(/列/阵),然后每行(/列/阵)都有九种数的情况.于是就有了3*9 ...
- [poj3074]Sudoku(舞蹈链)
题目链接:http://poj.org/problem?id=3074 舞蹈链精确覆盖的经典题目,一个数独每个位置的要求,可以得到以下四个约束1.每个位置有且只有一个数字2.每个位置的数字在一行只能出 ...
- 【Dancing Link专题】解题报告
DLX用于优化精确覆盖问题,由于普通的DFS暴力搜索会超时,DLX是一个很强有力的优化手段,其实DLX的原理很简单,就是利用十字链表的快速删除和恢复特点,在DFS时删除一些行和列以减小查找规模,使得搜 ...
随机推荐
- 前端chrome调试技巧
待更新:http://blog.csdn.net/xueer767/article/details/65936204?locationNum=8&fps=1
- treetable--.net webform中树形table表管理的应用
好记性不如烂笔头. treetable 官网:http://ludo.cubicphuse.nl/jquery-treetable/#api 今天要做一个关于table的树节点展示,还有编辑,删除功能 ...
- Python Map 并行
Map是一个酷酷的小东西,也是在Python代码轻松引入并行的关键.对此不熟悉的人会认为map是从函数式语言(如Lisp)借鉴来的东西.map是一个函数 - 将另一个函数映射到一个序列上.例如: ur ...
- VueJs 学习笔记
VueJs学习笔记 参考资料:https://cn.vuejs.org/ 特效库:TweenJS(补间动画库) VelocityJS(轻量级JS动画库) Animate.css(CSS预设动画库) ...
- RabbitMQ基础教程之使用进阶篇
RabbitMQ基础教程之使用进阶篇 相关博文,推荐查看: RabbitMq基础教程之安装与测试 RabbitMq基础教程之基本概念 RabbitMQ基础教程之基本使用篇 I. 背景 前一篇基本使用篇 ...
- 腾讯云API弹性公网IP踩坑
由于自己管理的云服务器数量比较多,时不时需要更换IP,在管理台上一下下点击,实在浪费时间,于是就想到了通过API调用的方式,将更换IP一系列动作,全部集成到Python代码里面,实现一行命令,完成IP ...
- SQL 从入门到 DBA 删库跑路
SQL 从入门到 DBA 删库跑路 一.基础 人员信息表: ID 姓名 性别 出生 婚否 学历 工资 工会 35009449 孙xx 男 1978-2-17 未婚 中专 3000 TRUE 35000 ...
- Javascript打印网页局部的实现方案
项目中,需要对页面的部分div进行打印,为了保证界面布局不乱,采取了新建iframe的方法. 将需要打印的div放到iframe中,然后调用iframe进行打印,就可以很好的实现局部打印的效果了. 同 ...
- C#冒泡排序法及优化
冒泡排序法及优化: static void Main(string[] args) { , , , , , }; ; //冒泡排序法 ; i < sums.Length - ; i++) //总 ...
- Oracle存储过程练习题
1.1.创建一个过程,能向dept表中添加一个新记录.(in参数) 创建过程 create or replace procedure insert_dept ( num_dept in number, ...