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时删除一些行和列以减小查找规模,使得搜 ...
随机推荐
- C#从Gif中提取图片
C#从Gif中提取图片的代码片段 private void btn_extract_Click(object sender, EventArgs e) { Image imgGif = Image.F ...
- fastjson处理json
返回主页 你是风儿 博客园首页新随笔联系订阅管理 随笔 - 29 文章 - 0 评论 - 23 FastJson对于JSON格式字符串.JSON对象及JavaBean之间的相互转换 fastJson对 ...
- 一 Hive安装及初体验
一 .Hive安装及初体验 1 .hive简介 Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能. 1.1直接使用hadoop面临的问题 ...
- Mac brew安装redis
1.安装redis $ brew install redis Error:Failed to download resource "reds" // 下载reds失败 不过不需要 ...
- Qt 计算两个日前间隔天数
某一个大神写的 改写了一点 请无视注释 //时间计算法则 /********************************************************************** ...
- 不老的神器--namp,awvs
要会使用的工具 NESSUS nmap awvs hydra burpsuit 工具的话,都有文档,应该多使用 -h 多看官方文档,就会用了. 1.namp基本用法 -iL <inputfile ...
- Kotlin Android Extensions: 与 findViewById 说再见 (KAD 04) -- 更新版
作者:Antonio Leiva 时间:Aug 16, 2017 原文链接:https://antonioleiva.com/kotlin-android-extensions/ 在 Kotlin1. ...
- svn清理报错:Cleanup failed to process the following paths
这里碰到svn更新时,提示清理,清理时报错: 只需进行以下几个步骤即可解决:(原理即是清除掉svn数据库里的lock记录) 1.下载SQLiteManager,svn用的是sqlite数据库,需要一款 ...
- C++11 type_traits 之is_pointer,is_member_function_pointer源码分析
源码如下: template<typename> struct __is_pointer_helper : public false_type { }; template<typen ...
- 技本功丨知否知否,Redux源码竟如此意味深长(下集)
上集回顾 Redux是如何使用的?首先再来回顾一下这个使用demo(谁让这段代码完整地展示了redux的使用) 如果有小伙伴对这段代码不是很理解的话,建议先去学习Redux的使用再来看这篇源码,这样更 ...