洛谷 P1784 数独[DFS/回溯]
To 洛谷.1784 数独类似题:CODEVS.4966 简单数独(4*4数独) CODEVS.2924 数独挑战)
题目描述
数独是根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫内的数字均含1-9,不重复。每一道合格的数独谜题都有且仅有唯一答案,推理方法也以此为基础,任何无解或多解的题目都是不合格的。
芬兰一位数学家号称设计出全球最难的“数独游戏”,并刊登在报纸上,让大家去挑战。
这位数学家说,他相信只有“智慧最顶尖”的人才有可能破解这个“数独之谜”。
据介绍,目前数独游戏的难度的等级有一道五级,一是入门等级,五则比较难。不过这位数学家说,他所设计的数独游戏难度等级是十一,可以说是所以数独游戏中,难度最高的等级他还表示,他目前还没遇到解不出来的数独游戏,因此他认为“最具挑战性”的数独游戏并没有出现。
输入输出格式
输入格式:
一个未填的数独
输出格式:
填好的数独
输入输出样例
8 0 0 0 0 0 0 0 0
0 0 3 6 0 0 0 0 0
0 7 0 0 9 0 2 0 0
0 5 0 0 0 7 0 0 0
0 0 0 0 4 5 7 0 0
0 0 0 1 0 0 0 3 0
0 0 1 0 0 0 0 6 8
0 0 8 5 0 0 0 1 0
0 9 0 0 0 0 4 0 0
8 1 2 7 5 3 6 4 9
9 4 3 6 8 2 1 7 5
6 7 5 4 9 1 2 8 3
1 5 4 2 3 7 8 9 6
3 6 9 8 4 5 7 2 1
2 8 7 1 6 9 5 3 4
5 2 1 9 7 4 3 6 8
4 3 8 5 2 6 9 1 7
7 9 6 3 1 8 4 5 2
[分析]:
用三个数组进行标记每行、每列、每个子网格已用的数字,用于剪枝
bool row[10][10]; //row[i][x] 标记在第i行中数字x是否出现了
bool col[10][10]; //col[j][y] 标记在第j列中数字y是否出现了
bool g[10][10]; //g[k][x] 标记在第k个3*3子格中数字z是否出现了
row 和 col的标记比较好处理,关键是找出g子网格的序号与 行i列j的关系
即要知道第i行j列的数字是属于哪个子网格的
首先我们假设子网格的序号如下编排:
由于1<=i、j<=9,我们有: (其中“/”是C++中对整数的除法)
令a= i/3 , b= j/3 ,根据九宫格的 行列 与 子网格 的 关系,我们有:
不难发现 3a+b=k
即 3*(i/3)+j/3=k
又我在程序中使用的数组下标为 1~9,grid编号也为1~9
因此上面的关系式可变形为 3*((i-1)/3)+(j-1)/3+1=k(第k个3*3子格中)
这样我们就能记录k个3*3子格中数字z是否出现了:
[代码]:
#include<cstdio>
#include<cstring>
#include<cstdlib>
int a[][];
bool h[][],l[][],g[][];//行,列,第几个格子
void print()//输出函数
{
for(int i=;i<=;i++)
{
for(int j=;j<=;j++)
printf("%d ",a[i][j]);
printf("\n");
}
exit();
} void dfs(int x,int y)//深搜
{
if(a[x][y]!=)//9*9中不为零的数直接跳过
{
if(x==&&y==)
print(); //搜索结束后输出
if(y==) //行到顶端后搜索列
dfs(x+,);
else //搜索行
dfs(x,y+);
}
if(a[x][y]==)//等于零时 待填数!
{
for(int i=;i<=;i++)
{ //true未访问过
if( h[x][i] && l[y][i] && g[(x-)/*+(y-)/+][i] ) //((i-1)/3)*3+(j-1)/3+1
{
a[x][y]=i; //从1试到9
h[x][i]=false;//此格被占 (行)
l[y][i]=false;//同上(列)
g[(x-)/*+(y-)/+][i]=false;//同上 (格子) if(x==&&y==) //同a[x][y]!=0时
print();
if(y==)
dfs(x+,);
else
dfs(x,y+); a[x][y]=; //当前格退出返回初状态
h[x][i]=true;
l[y][i]=true;
g[(x-)/*+(y-)/+][i]=true;
}
}
}
} int main()
{
memset(h,true,sizeof(h));
memset(l,true,sizeof(l));
memset(g,true,sizeof(g));
for(int i=;i<=;i++)
{
for(int j=;j<=;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]>)
{
h[i][a[i][j]]=false;//表示格子上有数
l[j][a[i][j]]=false;//同上
g[(i-)/*+(j-)/+][a[i][j]]=false;//同上
}
}
}
dfs(,);
puts("\n");
return ;
}
DFS
/*
根据二进制的思想,用二进制的第i位是0或1来表示数字是否已出现。
用 | 运算符进行标记,
用 ^ 运算符去标记,
用 & 运算符进行判重,
这样只需要一维的数组。
*/
#include<cstdio>
#define z(i) (1<<i)
#define g(x,y) (3*((x-1)/3)+(y-1)/3+1)
int h[],l[],s[],f[][],ok,sum=;
int read()
{
int _=,___=;char __=getchar();
while(__<''||__>''){if(__=='-')___=-;__=getchar();}
while(__>=''&&__<=''){_=_*+__-'';__=getchar();}
return _*___;
}
void out()
{
for(int i=;i<=;i++)
{
for(int j=;j<=;j++)
printf("%d ",f[i][j]);
printf("\n");
}
}
void dfs(int x,int y,int tot)
{
while(f[x][y])
{
y++;
if(y>) x++,y=;
}
for(int i=;i<=;i++)
{
if(h[x]&z(i)||l[y]&z(i)||s[g(x,y)]&z(i)) continue; //用 & 运算符进行判重 f[x][y]=i; h[x]|=z(i); l[y]|=z(i); s[g(x,y)]|=z(i); //用 | 运算符进行标记 if(tot==sum) ok=;
else dfs(x,y,tot+);
if(ok) return ; f[x][y]=; h[x]^=z(i); l[y]^=z(i); s[g(x,y)]^=z(i); //用 ^ 运算符去标记
}
}
int main()
{
for(int i=;i<=;i++)
for(int x,j=;j<=;j++)
{
f[i][j]=x=read();
if(!x)continue;
h[i]|=z(x); l[j]|=z(x); s[g(i,j)]|=z(x);
sum--;
}
dfs(,,);
out();
return ;
}
状态压缩dfs
洛谷 P1784 数独[DFS/回溯]的更多相关文章
- 洛谷P1784 数独
To 洛谷.1784 数独(类似(或者说相同)题:CODEVS.4966 简单数独(4*4数独) CODEVS.2924 数独挑战) 题目描述 数独是根据9×9盘面上的已知数字,推理出所有剩余空格的数 ...
- 洛谷 P1784 数独
题目描述 数独是根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个粗线宫内的数字均含1-9,不重复.每一道合格的数独谜题都有且仅有唯一答案,推理方法也以此为基础,任何无 ...
- 洛谷—— P1784 数独
https://www.luogu.org/problem/show?pid=1784 题目描述 数独是根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个粗线宫内的数字 ...
- P1074 靶形数独 dfs回溯法
题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士拿出了他最近发明的“靶 ...
- 填写数独 洛谷P1784
题目链接:https://www.luogu.org/problemnew/show/P1784 因为要求行列以及每9个数字组成的中格子都得有1-9这9个数,我们不妨建三个二维数组 第一维代表是第几个 ...
- 【POJ - 2676】Sudoku(数独 dfs+回溯)
-->Sudoku 直接中文 Descriptions: Sudoku对数独非常感兴趣,今天他在书上看到了几道数独题: 给定一个由3*3的方块分割而成的9*9的表格(如图),其中一些表格填有1- ...
- 洛谷P1731生日蛋糕(dfs+剪枝)
P1731 生日蛋糕 题目背景 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层 生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1<=i<=M)层蛋糕是半径为R ...
- 洛谷1002 容斥原理+dfs OR DP
//By SiriusRen #include <bits/stdc++.h> using namespace std; #define int long long ,,,,-,-,-,- ...
- luogu P1784 数独 dfs 舞蹈链 DXL
LINK:数独 这道题好难 比DXL模板题要难上不少. 首先 还是考虑将行当做决策 那么 一共有\(9*9*9=729\) 个决策. 考虑列用来填充 需要有的条件为 某个位置能能放一次\(9*9\) ...
随机推荐
- mysql同步故障解决
故障现象:Slave_SQL_Running: No Slave状态:mysql> show slave status\GSlave_IO_Running: YesSlave_SQL_Runni ...
- 【Todo】 cygwin下emacs中M-x shell 中出现乱码
- kafka 的offset的重置
最近在spark读取kafka消息时,每次读取都会从kafka最新的offset读取.但是如果数据丢失,如果在使用Kafka来分发消息,在数据处理的过程中可能会出现处理程序出异常或者是其它的错误,会造 ...
- IE下Date.parse出现NaN有关问题解决
IE不支持"2000-01-01"这种格式的,但是谷歌浏览器支持,改成"2000/01/01"就可以了. 下面的方法两种浏览器就就都支持了 Date.parse ...
- 关于html头部引用(meta,link)
/*这一段头部表示 如果安装了GCF,则使用GCF来渲染页面,如果为安装GCF,则使用最高版本的IE内核进行渲染.*/<meta content="IE=edge,chrome=1&q ...
- 可拖动jquery插件
http://www.open-open.com/ajax/DragDrop.htm http://sc.chinaz.com/info/130722592854.htm http://sc.itcn ...
- centOS6.6虚拟机启动后登陆界面无法显示
1.图一和图二对比就很明显发现,我的登陆界面不见了(突然断电导致不正常关机,造成图形界面桌面崩溃) 2.解决方法:启动按Ctrl+Alt+f2切换进命令行界面,root账号进入,重新下载图形界面
- android adb常用指令
介绍一个更详细的介绍ADB的: https://github.com/mzlogin/awesome-adb/blob/master/README.md ----------------------- ...
- noip 2018 d2t1 旅行
noip 2018 d2t1 旅行 (题目来自洛谷) 给定n个城市,m条双向道路的图, 不存在两条连接同一对城市的道路,也不存在一条连接一个城市和它本身的道路.并且, 从任意一个城市出发,通过这些道路 ...
- Java开发微信公众号(三)---微信服务器请求消息,响应消息,事件消息以及工具处理类的封装
在前面几篇文章我们讲了微信公众号环境的配置 和微信公众号服务的接入,接下来我们来说一下微信服务器请求消息,响应消息以及事件消息的相关内容,首先我们来分析一下消息类型和返回xml格式及实体类的封装. ( ...