数独(深搜)数据最弱版本(poj 2676)

Description

Sudoku is a very simple task. A square table with 9 rows and 9 columns is divided to 9 smaller squares 3x3 as shown on the Figure. In some of the cells are written decimal digits from 1 to 9. The other cells are empty. The goal is to fill the empty cells with decimal digits from 1 to 9, one digit per cell, in such way that in each row, in each column and in each marked 3x3 subsquare, all the digits from 1 to 9 to appear. Write a program to solve a given Sudoku-task.

Input

The input data will start with the number of the test cases. For each test case, 9 lines follow, corresponding to the rows of the table. On each line a string of exactly 9 decimal digits is given, corresponding to the cells in this line. If a cell is empty it is represented by 0.

Output

For each test case your program should print the solution in the same format as the input data. The empty cells have to be filled according to the rules. If solutions is not unique, then the program may print any one of them.

Sample Input
1
103000509
002109400
000704000
300502006
060000050
700803004
000401000
009205800
804000107
Sample Output
143628579
572139468
986754231
391542786
468917352
725863914
237481695
619275843
854396127
分析
  • 可以从左上角一行一行扫描到右下角,对于每一个块列举每一种可能,然后从每个可能出发继续深度遍历直到发现有一个块没有数字可以填时停止
  • 如何储存每一块可以填写的数字?可以利用九位二进制数来表示每一行,每一列,每个九宫格的数字填写情况,然后直接对这三个数字做按位与运算就可以得到某一具体块可以填的数字了。
  • 这里直接用bitset,对于每一个结果,直接遍历一下就可以了。
char a[15][15];
int b[11][11];
bitset<10> row[10],col[10],room[10];
inline int g(int i,int j)//计算i,j对应的块的序号
{
return ((i-1)/3)*3+((j-1)/3)+1;
}
void init()
{
//把每个九位二进制数都全部置位1,表示可以填
for(int i=1;i<=9;i++)
{
row[i].set();
col[i].set();
room[i].set();
}
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
int x = a[i][j]-'0';
b[i][j] = x;
//如果不是0,就要更新该行该列该九宫格的数字填写范围了
if(x)
{
row[i][x] = 0;
col[j][x] = 0;
room[g(i,j)][x] = 0;
}
}
}
}
bool dfs(int x,int y)
{
//如果扫描到了第10行,返回正确
if(x==10)
return true;
bool flag = false;
if(b[x][y])
{
if(y==9)//如果扫描到行末,继续扫描下一行行首
flag = dfs(x+1,1);
else
flag = dfs(x,y+1);
if(flag)
return true;
else
return false;
}
int k = g(x,y);
bitset<10> tmp = row[x]&col[y]&room[k];//得到该处可填写的数字二进制表示
//cout<<tmp<<endl;
for(int i=1;i<=9;i++)
{
if(tmp[i]==1)//如果可以填写i
{
b[x][y] = i;
row[x][i] = 0;
col[y][i] = 0;
room[k][i] = 0;
if(y==9)
flag = dfs(x+1,1);
else
flag = dfs(x,y+1);
if(flag)
return true;
row[x][i] = 1;
col[y][i] = 1;
room[k][i] = 1;
b[x][y] = 0;
}
}
return false;
} int main()
{
int t;
cin>>t;
while(t--)
{
for(int i=1;i<=9;i++)
{
scanf("%s",a[i]+1);
}
init();
dfs(1,1);
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
cout<<b[i][j];
}
cout<<endl;
}
}
return 0;
}

数独(深搜,剪枝)数据较强版本(poj 3074)

Description

In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example,

.	2	7	3	8	.	.	1	.
. 1 . . . 6 7 3 5
. . . . . . . 2 9
3 . 5 6 9 2 . 8 .
. . . . . . . . .
. 6 . 1 7 4 5 . 3
6 4 . . . . . . .
9 5 1 8 . . . 7 .
. 8 . . 6 5 3 4 .

Given some of the numbers in the grid, your goal is to determine the remaining numbers such that the numbers 1 through 9 appear exactly once in (1) each of nine 3 × 3 subgrids, (2) each of the nine rows, and (3) each of the nine columns.

Input

The input test file will contain multiple cases. Each test case consists of a single line containing 81 characters, which represent the 81 squares of the Sudoku grid, given one row at a time. Each character is either a digit (from 1 to 9) or a period (used to indicate an unfilled square). You may assume that each puzzle in the input will have exactly one solution. The end-of-file is denoted by a single line containing the word “end”.

Output

For each test case, print a line representing the completed Sudoku puzzle.

Sample Input
.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
Sample Output
527389416819426735436751829375692184194538267268174593643217958951843672782965341
416837529982465371735129468571298643293746185864351297647913852359682714128574936

分析:

  • 如果我们依然像上道题一样从左上角找到右下角,这道题会很容易Tl的,所以我们要变得更加聪明一点,正如我们做数独的话,肯定是先找最容易确定的位置去填,所以我们可以在搜索时先找到81个空中可填数最少的空
  • 深搜时,我们需要的状态就是还没有填的数,这是我们所关心的,如果没有要填的空,就返回true,如果在找最小可填数时有一个空发现没有可以填的数字,则直接返回false
  • 另外我们可以直接使用二进制运算lowbit,再加上一个数组num[],就可以直接查找到对于每一种可能的具体数字。
  • 因为我们是用二进制储存可填数的,所以在更新这些数字时,只是单纯的把某一位进行取反,所以我们可以直接用一个flip函数,巧妙地减少了代码量。
#include <stdio.h>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s, 0, sizeof(s))
const int inf = 0x3f3f3f3f;
#define LOCAL
char a[100];
char b[11][11];
int row[10], col[10], room[10], cnt[513], num[512];
inline int g(int i,int j)
{
return ((i-1)/3)*3+((j-1)/3)+1;
}
inline void flip(int x, int y, int z) {
row[x] ^= 1 << z;
col[y] ^= 1 << z;
room[g(x, y)] ^= 1 << z;
}
bool dfs(int tot)
{
if(tot==0)
return true;
int tmp = 10,x,y;
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
{
if(b[i][j] != '.')continue;
int val = col[j]&row[i]&room[g(i,j)];
if(!val)return false;//重点
if (cnt[val]< tmp)
{
tmp = cnt[val];
x = i, y = j;
}
}
int val = row[x]&col[y]&room[g(x,y)];
for(;val;val -= val&-val)
{
int z = num[val&-val];
b[x][y] = z + '1';
flip(x,y,z);
if(dfs(tot-1))
{
return true;
}
flip(x,y,z);
b[x][y] = '.';
}
return false;
}
void init()
{
for(int i=1;i<=9;i++)
row[i]=col[i]=room[i]=(1<<9)-1;//全部赋值成1
int tot = 0;
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
{
b[i][j] = a[(i-1)*9+j-1];
if(b[i][j]!='.')
flip(i,j,b[i][j]-'1');//因为二进制的第1位表示1是否可填,为了配合filp函数,这里传参b[i][j]-'1'
else
tot++;
}
dfs(tot);
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
a[(i-1)*9+j-1] = b[i][j];
} int main()
{
for (int i = 0; i < 1 << 9; i++)
for (int j = i; j; j -= j&-j)
cnt[i]++;//对于每一个九位二进制数,储存它二进制表示中1的个数
for (int i = 0; i <= 9; i++)
num[1 << i] = i;//储存二进制中每一位1的权值
while(scanf("%s",a))
{
if(a[0]=='e')
break;
init();
puts(a);
}
return 0;
}

poj3076是一个16宫格的数独,日后再战。

数独(深搜)(poj2726,poj3074)的更多相关文章

  1. [NOIP2009]靶形数独 深搜+枝杈优化

    这道题,又是一位玄学搜索...... 我是用的蜗牛序搜的(顾名思义,@,这么搜),我正着搜80然后一反转比原来快了几十倍........一下AC....... 我的思路是这样的话我们可以从内到外或者从 ...

  2. (hdu)5547 Sudoku (4*4方格的 数独 深搜)

    Problem Description Yi Sima was one of the best counselors of Cao Cao. He likes to play a funny game ...

  3. HDU--杭电--1195--Open the Lock--深搜--都用双向广搜,弱爆了,看题了没?语文没过关吧?暴力深搜难道我会害羞?

    这个题我看了,都是推荐的神马双向广搜,难道这个深搜你们都木有发现?还是特意留个机会给我装逼? Open the Lock Time Limit: 2000/1000 MS (Java/Others)  ...

  4. 利用深搜和宽搜两种算法解决TreeView控件加载文件的问题。

    利用TreeView控件加载文件,必须遍历处所有的文件和文件夹. 深搜算法用到了递归. using System; using System.Collections.Generic; using Sy ...

  5. 2016弱校联盟十一专场10.3---Similarity of Subtrees(深搜+hash、映射)

    题目链接 https://acm.bnu.edu.cn/v3/problem_show.php?pid=52310 problem description Define the depth of a ...

  6. 2016弱校联盟十一专场10.2---Around the World(深搜+组合数、逆元)

    题目链接 https://acm.bnu.edu.cn/v3/problem_show.php?pid=52305 problem  description In ICPCCamp, there ar ...

  7. 2015暑假多校联合---Cake(深搜)

    题目链接:HDU 5355 http://acm.split.hdu.edu.cn/showproblem.php?pid=5355 Problem Description There are m s ...

  8. 深搜+回溯 POJ 2676 Sudoku

    POJ 2676 Sudoku Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 17627   Accepted: 8538 ...

  9. 深搜+DP剪枝 codevs 1047 邮票面值设计

    codevs 1047 邮票面值设计 1999年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题目描述 Description ...

随机推荐

  1. LIS LCS LCIS (主要过一遍,重在做题)

    只详细讲解LCS和LCIS,别的不讲-做题优先. 菜鸟能力有限写不了题解,可以留评论,我给你找博客. 先得理解最长上升子序列吧,那个HDOJ拦截导弹系列可以做一下,然后用o(n)log(n)的在做一遍 ...

  2. P4171 [JSOI2010]满汉全席(2-SAT)

    传送门 2-SAT裸题 把每一道菜拆成两个点分别表示用汉式或满式 连边可以参考板子->这里 然后最尴尬的是我没发现$n<=100$然后化成整数的时候只考虑了$s[1]$结果炸掉了2333 ...

  3. 黑客攻防技术宝典web实战篇:攻击验证机制习题

    猫宁!!! 参考链接:http://www.ituring.com.cn/book/885 随书答案. 1. 在测试一个使用joe和pass证书登录的Web应用程序的过程中,在登录阶段,在拦截代理服务 ...

  4. (二)SpringBoot整合常用框架Druid连接池

    一,在Pom.xml文件加入依赖 找到<dependencies></dependencies>标签,在标签中添加Druid依赖 <dependency> < ...

  5. 语句 if

    1.if语句单项分支 #单项分支 if 55 < 133: print('这个比较运算是正确的') #输出结果:这个比较运算是正确的 2.if语句双项分支 #双项分支 if 55 > 14 ...

  6. cmd - 批量重命名文件

    相信大家或多或少都遇到过类似的情况:从网上下载了好多图片(或者其他的文件),这些图片的名字往往都是些乱七八糟的字母数字的组合,我们想要一次性修改几十张上百张的图片的名字应该怎么办呢? 这里有两种方法, ...

  7. 网站如何从http升级成https

    基本概念: HTTP: 是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准,用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少. HT ...

  8. System.Web.Mvc 和 using System.Net.Http 的 Filter

    在尝试给webapi增加 ExceptionFilter时,出现了错误,经查询区别如下: System.Web.Mvc.Filters 是给mvc用的 System.Web.Http.Filters ...

  9. HttpURLConnection 发送PUT请求 json请求体 与服务端接收

    发送请求: public void testHttp() { String result = ""; try { URL postURL = new URL("http: ...

  10. python staticmethod&classmethod

    python中的这两种方法都通过修饰器来完成 静态方法: 不需要传递类对象或者类的实例 可以通过类的实例.方法名a().foo()或者类名.方法a.foo()名来访问 当子类继承父类时,且实例化子类时 ...