洛谷 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\) ...
随机推荐
- 动态规划:HDU-1398-Square Coins(母函数模板)
解题心得: 1.其实此题有两种做法,动态规划,母函数.个人更喜欢使用动态规划来做,也可以直接套母函数的模板 Square Coins Time Limit: 2000/1000 MS (Java/Ot ...
- SSH无密码登录及远程拷贝命令SCP的使用
SSH无密码登录 1.生成密钥对(公钥和私钥) $ cd /home/cen/.ssh $ ssh-keygen -t rsa #生成密钥,使用rsa方式进行加密,四个回车 $ ssh-copy-id ...
- mac terminal基本命令
文件目录 首先要清楚几个文件目录: " / " :根目录 " ~ " :用户主目录的缩写.例如当前用户为esther,那么" ~ "展开来 ...
- P3376 【模板】网络最大流dinic算法
P3376 [模板]网络最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点 ...
- LINUX下实现按秒执行计划任务
由于linux最小单位为分,但是很多需求上需要按秒执行,如30秒请求一个URL地址之类的,思路很简单就是修改计划任务脚本用循环控制,代码如下: #!/bin/bash PATH=/bin:/sbin: ...
- itchat 总结(转)
python实现微信接口(itchat) 安装 sudo pip install itchat 登录 itchat.auto_login() 这种方法将会通过微信扫描二维码登录,但是这种登录的方式确实 ...
- 43、gridview或者listview的adapter优化
1.在getview时,如果是一个textview,那么不用每次都new一个或者inflater直接返回,可以先判断convertview是否为空,如果为空则new或者inflate,否则直接返回co ...
- 【Jump Game II 】cpp
题目: Given an array of non-negative integers, you are initially positioned at the first index of the ...
- leetcode 【 Unique Paths 】python 实现
题目: A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). ...
- rule.xml属性概念
# tableRule <tableRule name="rule1"> <rule> <columns>id</columns> ...