AcWing 166. 数独
题目地址 https://www.acwing.com/problem/content/description/168/
题目描述
数独是一种传统益智游戏,你需要把一个9 × 9的数独补充完整,使得图中每行、每列、每个3 × 3的九宫格内数字1~9均恰好出现一次。
请编写一个程序填写数独。
输入格式
输入包含多组测试用例。
每个测试用例占一行,包含81个字符,代表数独的81个格内数据(顺序总体由上到下,同行由左到右)。
每个字符都是一个数字(1-9)或一个”.”(表示尚未填充)。
您可以假设输入中的每个谜题都只有一个解决方案。
文件结尾处为包含单词“end”的单行,表示输入结束。
输出格式
每个测试用例,输出一行数据,代表填充完全后的数独。
样例
输入样例:
...............293.5692............6.1745................
........8.4............5.1.................................7.4........
end
输出样例:
法1
时间卡的比较紧,搜索上做了许多优化
1 进行可填写数据的筛选.由于数独本身的性质,1~9同一数字不能在同一行 同一列 同一九宫格出现两次以上。
我开始计划是开一个 9*9的数组记录每个格子可能出现的数字.每次确认填写一个数字 就更新同行同列同九宫格里的记录
但是这样的话,每次填写一个数字及需要更新 一行9个 一列9个 和九宫格九格的数据。共27个数据。
YXC大佬的代码 使用的 行记录一个 列记录一个 九宫格记录一个 这样只需要更新三个数据即可
2 优化填写格子的策略,每个格子可填写的数据比较少的优先选取。 这也是剪枝的一种.
代码见
//找到可选方案数最少的空格
int minv = ;
int x, y;
for(int i = ;i < N;i++)
for(int j = ;j < N;j++)
if (str[i*+j] == '.') {
int t = ones[get(i, j)];
if (t < minv) {
minv = t;
x = i, y = j;
}
}
3 一些其他小技巧,使用位来记录该空格可填写那些数字
000000001 表示可填写1
000000010 表示可填写2
000000100 表示可填写3
000000101 表示可填写1和3
......
x = 000000111 表示可填写1 2 3。 如果我们当前选择填写2 那么只要 x - (1<<(2-1))就可以把填写2的表示去除了
代码里不是2-1 而是 可填写的数字的字母的实际值与 ‘1’的差值
4 判断是否是统一九宫格 采用 x/3==i/3 y/3 == j/3
还有其他一些小技巧 欢迎一起讨论
#include <iostream>
#include <algorithm>
#include <set> using namespace std; const int N = ; int row[N], col[N],cell[][]; char str[]; int ones[ << N],map[<<N]; inline int lowbit(int x) {
return x & -x;
} void init()
{
for (int i = ; i < N; i++) row[i] = col[i] = ( << N) - ;
for (int i = ; i < ; i++)
for (int j = ; j < ; j++)
cell[i][j] = ( << N) - ;
} inline int get(int x, int y)
{
return row[x] & col[y] & cell[x / ][y / ]; } bool dfs(int cnt)
{
if (!cnt) return true; //找到可选方案数最少的空格
int minv = ;
int x, y;
for(int i = ;i < N;i++)
for(int j = ;j < N;j++)
if (str[i*+j] == '.') {
int t = ones[get(i, j)];
if (t < minv) {
minv = t;
x = i, y = j;
}
} for (int i = get(x, y); i; i -= lowbit(i)) {
int t = map[lowbit(i)]; //修改状态
row[x] -= << t;
col[y] -= << t;
cell[x / ][y / ] -= << t;
str[x * + y] = '' + t;
if (dfs(cnt - )) return true; //回复现场
row[x] += << t;
col[y] += << t;
cell[x / ][y / ] += << t;
str[x * + y] = '.';
} return false;
} int main()
{
for (int i = ; i < N; i++) map[ << i] = i;
for (int i = ; i < << N; i++) {
int s = ;
for(int j = i; j;j -= lowbit(j)) s++;
ones[i] = s; //i的二进制表示中有s个1
} while (cin >> str, str[] != 'e') {
init();
int cnt = ;
for(int i =,k = ;i < N;i++)
for(int j = ; j < N;j++,k++)
if (str[k] != '.') {
int t = str[k] - '';
row[i] -= << t;
col[j] -= << t;
cell[i / ][j / ] -= << t;
}
else {
cnt++;
} dfs(cnt);
cout << str << endl;
} return ; } 作者:defddr
链接:https://www.acwing.com/solution/AcWing/content/2294/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
// 11111111.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// #include <iostream>
#include <map>
#include <vector>
#include <string>
#include <stdio.h> using namespace std; /*
.2738..1..1...6735.......293.5692.8...........6.1745.364.......9518...7..8..6534.
......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.
end
*/ const int N = ; int map1[ << N];
int Xarr[N];
int Yarr[N];
int SameXYArr[N / ][N / ]; int ones[ << N], map[ << N]; char str[]; void Init()
{
for (int i = ; i < N; i++) {
Xarr[i] = ( << N) - ;
Yarr[i] = ( << N) - ;
map1[ << i] = i;
} for (int i = ; i < N / ; i++) {
for (int j = ; j < N / ; j++) {
SameXYArr[i][j] = ( << N) - ;
}
}
} inline int lowbit(int x) {
return x & -x;
} inline int get(int x, int y)
{
return Xarr[x] & Yarr[y] & SameXYArr[x / ][y / ];
} bool Dfs(int count, char str[])
{
if (!count) return true; int minv = ;
int minx = -; int miny = -; for (int x = ; x < ; x++) {
for (int y = ; y < ; y++)
{
if (str[x * + y] == '.') {
int t = ones[get(x,y)]; if (t < minv) {
minv = t;
minx = x;
miny = y;
}
}
}
} if ( == minv)
return false; int tryNums = get(minx, miny); while (tryNums != ) {
int trynum = map1[lowbit(tryNums)]; Xarr[minx] -= << trynum;
Yarr[miny] -= << trynum;
SameXYArr[minx / ][miny / ] -= << trynum;
str[minx * + miny] = '' + trynum; if (Dfs(count - , str)) return true; //回复现场
Xarr[minx] += << trynum;
Yarr[miny] += << trynum;
SameXYArr[minx / ][miny / ] += << trynum;
str[minx * + miny] = '.'; tryNums -= lowbit(tryNums);
} return false;
} void Do(char str[])
{
Init();
int count = ;
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
if (str[i * + j] != '.') {
int idx = << (str[i * + j] - '');
Xarr[i] -= idx;
Yarr[j] -= idx;
SameXYArr[i / ][j / ] -= idx;
}
else {
count++;
}
}
} Dfs(count, str);
cout << str << endl; return;
} int main()
{
ios::sync_with_stdio(false); for (int i = ; i < N; i++) map1[ << i] = i;
for (int i = ; i < << N; i++) {
int s = ;
for (int j = i; j; j -= lowbit(j)) s++;
ones[i] = s; //i的二进制表示中有s个1 } while (cin >> str, str[] != 'e') {
//s = ".2738..1..1...6735.......293.5692.8...........6.1745.364.......9518...7..8..6534."; Do(str);
} }
AcWing 166. 数独的更多相关文章
- 166. 数独 dancing links 方法
dfs硬怼通过数独 N皇后的代码后 想学习下新的数据结构和算法来解决这类覆盖问题 习题练习 https://www.acwing.com/problem/content/168/ 数独 https:/ ...
- Swift数独游戏优化——C++与OC混编、plist自动生成
一.为什么要C++与OC混编? 在我之前的数独游戏中涉及到的数独游戏生成算法是参考的网上其他人的算法,是利用C++来实现的. 但是在我的例子中我发现这样存在一定的局限性: 1.我是利用Termin ...
- iOS开发 Swift开发数独游戏(二)数独题目的生成
一.Plist文件结构设计 由于要预先生成数独题目的文件,我自然而然想到用plist存取. 我用Xcode建了几个plist文件来熟悉这种文件使用的结构后设计了如下结构: 为区分难度(后来了解到挖空数 ...
- iOS开发 Swift开发数独游戏(四) 游戏界面的界面与逻辑
一.游戏界面涉及到的功能点 1)数独格子的建模 (1)绘制数独格子要考虑到标记功能 所以要在每个格子内预先塞入9个标记数字,仅数独格子算下来就有9*9*9=729个格子且存在大量嵌套(这导致我在操作S ...
- LintCode389.判断数独是否合法
LintCode简单题:判断数独是否合法 问题描述: 请判定一个数独是否有效. 该数独可能只填充了部分数字,其中缺少的数字用 . 表示. 注意事项: 一个合法的数独(仅部分填充)并不一定是可解的.我们 ...
- [LeetCode] Sudoku Solver 求解数独
Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...
- [LeetCode] Valid Sudoku 验证数独
Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku board could be ...
- 数独 JAVA实现
数独游戏的规则从很久之前就知道,但是一直都没怎么玩过,然后到了大学,大一下学期自己学dfs的时候,刚刚好碰到了一个数独的题目,做出来后,感觉还是挺有成就感的 然后大二学了JAVA,看了下那个一些有关于 ...
- 用C++实现的解数独(Sudoku)程序
我是一个C++初学者,控制台实现了一个解数独的小程序. 代码如下: //"数独游戏"V1.0 //李国良于2016年11月11日编写完成 #include <iostream ...
随机推荐
- 精通awk系列(3):铺垫知识:读取文件的几种方式
回到: Linux系列文章 Shell系列文章 Awk系列文章 读取文件的几种方式 读取文件有如下几种常见的方式: 下面使用Shell的read命令来演示前4种读取文件的方式(第五种按字节数读取的方式 ...
- JVM学习分享-思考题
package zero.desk.stringconstantpool; import org.junit.Test; /** * @author Zero * @since 2019-09-17. ...
- MySQL语句使用。
目录 MySQL的DDL.DML.DQL语句和单表增.删.改.查 实验准备: 实验开始: DDL语句 DML语句 DQL语句 单表操作的分组统计 MySQL的DDL.DML.DQL语句和单表增.删.改 ...
- 一次在CentOS系统单用户模式下使用passwd命令破密失败的案例
某次遇到需要进入系统的单用户模式进行破密操作,结果却显示如下: 根据提示:Permission denied(缺少权限) 此时查看/usr/bin/passwd 权限: 正常情况下的权限应该是如下: ...
- 通过pywin32库来上传文件
先来安装:pip install pywin32 辅助定位工具winspy下载地址:https://sourceforge.net/projects/winspyex/ 打开后是这玩意: 按住靶心拖拽 ...
- 一天两道pat(3)1007,1008
1007没什么好说的,就是注意暴力求素数的时候,循环到(根号n)+1就好: 重点说说1008,不用新开一个数组就实现循环移位的操作 一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下 ...
- 关于java中三种初始化块的执行顺序
许多小伙伴对于java中的三种初始化块的执行顺序一直感到头疼,接下来我们就来分析一下这三种初始化块到底是怎么运行的.有些公司也会将这个问题作为笔试题目. 下面通过一段代码来看看创建对象时这么初始化块是 ...
- vue-cli2和cli3的使用和区别
vue-cli脚手架的使用 使用vue-cli可以快速搭建vue的开发环境,和webpack的配置 安装vue脚手架: npm install -g@vue/cli 上面安装的是vue cli3的版本 ...
- SpringBoot2.0 整合 SpringSecurity 框架,实现用户权限安全管理
本文源码:GitHub·点这里 || GitEE·点这里 一.Security简介 1.基础概念 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方 ...
- spring的简易实现(一)
[练习]spring的简易实现(一) 在第一部分我们实现读取xml的配置,然后实例化xml中的bean 首先定义一个xml和相关的class类 <?xml version="1.0&q ...