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时删除一些行和列以减小查找规模,使得搜 ...
随机推荐
- Caliburn.Micro 项目文档(翻译):Screens, Conductors and Composition
原文地址(项目说明文档):[Documentation Screens, Conductors and Composition]http://caliburnmicro.codeplex.com/w ...
- 北京Uber优步司机奖励政策(2月22日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- Java String源码解析
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { ...
- 2019年猪年海报PSD模板-第三部分
14套精美猪年海报,免费猪年海报,下载地址:百度网盘,https://pan.baidu.com/s/15m6sWTdDzuBfdmHYxJVvbA
- Appium Inspector定位元素与录制简单脚本
本次以微信为例, 使用Appium自带的Inspector定位工具定位元素, 以及进行最最最简单脚本的录制: capabilities = { "platformName": &q ...
- Python 多线程、进程、协程上手体验
浅谈 Python 多线程.进程.协程上手体验 前言:浅谈 Python 很多人都认为 Python 的多线程是垃圾(GIL 说这锅甩不掉啊~):本章节主要给你体验下 Python 的两个库 Thre ...
- Linux命令应用大词典-第21章 LVM和RAID管理
21.1 pvcreate:创建物理卷 21.2 pvscan:列出找到的物理卷 21.3 pvdisplay:显示物理卷的相关属性 21.4 vgcreate:创建卷组 21.5 vgscan:查找 ...
- pyhon文件操作典型代码实现(非常经典!)
1. 编写一个程序,统计当前目录下每个文件类型的文件数,程序实现如图: 实现代码: import os all_files = os.listdir(os.chdir("D:\\" ...
- JVM--内存模型与线程
一.硬件与效率的一致性 计算机的存储设备与处理器的运算速度存在几个数量级的差距,现在计算机系统不得不在内存和处理器之间增加一层高速缓存(cache)来作为缓冲.将运算需要的数据复制到缓存中,让运算能够 ...
- python基本数据类型——集合
集合 无序可变序列,集合中元素不允许重复,即每个元素都是唯一的 集合中的元素按照升序排列 # 创建集合 >>aset = set([0,2,4,5,7,2,3,5,9,0]) >&g ...