想了好久没想到好的解决办法,参考了 http://user.qzone.qq.com/289065406/blog/1303713313

大致题意:

九宫格问题,也有人叫数独问题

把一个9行9列的网格,再细分为9个3*3的子网格,要求每行、每列、每个子网格内都只能使用一次1~9中的一个数字,即每行、每列、每个子网格内都不允许出现相同的数字。

0是待填位置,其他均为已填入的数字。

要求填完九宫格并输出(如果有多种结果,则只需输出其中一种)

如果给定的九宫格无法按要求填出来,则输出原来所输入的未填的九宫格

解题思路:

DFS试探,失败则回溯

用三个数组进行标记每行、每列、每个子网格已用的数字,用于剪枝

bool row[10][10];    //row[i][x]  标记在第i行中数字x是否出现了

bool col[10][10];    //col[j][y]  标记在第j列中数字y是否出现了

bool grid[10][10];   //grid[k][x] 标记在第k个3*3子格中数字z是否出现了

row 和 col的标记比较好处理,关键是找出grid子网格的序号与 行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

 

 

有了这个推导的关系式,问题的处理就变得非常简单了,直接DFS即可

//Memory Time
//216K 422MS #include<iostream>
using namespace std;
//纵x 行y 即x行y列
int map[10][10]; //九宫格 bool row[10][10]; //row[i][x] 标记在第i行中数字x是否出现了
bool col[10][10]; //col[j][y] 标记在第j列中数字y是否出现了
bool grid[10][10]; //grid[k][x] 标记在第k个3*3子格中数字z是否出现了 //(这里说明的字母不代表下面程序中的变量) bool DFS(int x,int y)
{ //满足的条件是:找到最后一个 如果是true 那回溯上来都会是true 这是成立的情况 如果在中间出现false
//就要往前回溯 换个数字试试;
//成功的条件是
if(x==10)return true;//前面所有都满足了 已经没得找了
bool flag=false;
if(map[x][y]){
//if(x<9)DFS(x+1,y); //这样找的话会重复
//else if(y<9)DFS(x,y+1);
//所以我们一行一行找
if(y<9)
flag= DFS(x,y+1);
else flag=DFS(x+1,1);
return flag;//回溯 成功返回TRUE
}
else {
int k=3*((x-1)/3)+(y-1)/3+1; //k为第几个子方格
for(int i=1;i<=9;i++) //枚举数字1~9填空
{
if(row[x][i]==false&&col[y][i]==false&&grid[k][i]==false){
map[x][y]=i;
row[x][i]=true;
col[y][i]=true;
grid[k][i]=true;
//继续下找
if(y<9)
flag =DFS(x,y+1);
else flag=DFS(x+1,1);
if(flag==false){//不满足就原路返回
map[x][y]=0;
row[x][i]=false;
col[y][i]=false;
grid[k][i]=false;
}
else return true; } }
}
return false; //所有数字试过都不行的话
} int main()
{
int test;
int i,j;
char MAP[10][10];
cin>>test;
while(test--)
{
/*Initial*/ memset(row,false,sizeof(row));
memset(col,false,sizeof(col));
memset(grid,false,sizeof(grid)); /*Input*/
for(i=1;i<=9;i++)
for(j=1;j<=9;j++)
{
cin>>MAP[i][j]; //只能输入字符
map[i][j]=MAP[i][j]-'0';
if(map[i][j])//记录
{
int k=3*((i-1)/3)+(j-1)/3+1;
row[i][ map[i][j] ]=true;
col[j][ map[i][j] ]=true;
grid[k][ map[i][j] ]=true;
}
} /*Fill the Sudoku*/
DFS(1,1); for(i=1;i<=9;i++)
{
for(j=1;j<=9;j++)
cout<<map[i][j];
cout<<endl;
}
}
return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

POJ2676-Sudoku(数独)的更多相关文章

  1. POJ2676 Sudoku [数独]

    好题,也非常有用,犯了几个错误 1.在枚举赋值的时候,思维有个错误:当当前的赋值不能填完这个数独,应该是继续下一个循环,而不是return false 终止枚举 2.Generic Programin ...

  2. poj2676 Sudoku(DFS)

    做了很久还是参考了别人的答案orz,其实也不难啊.我要开始学一下怎么写搜索了... 题目链接:poj2676 Sudoku 题解:暴力搜索,DFS每个空白格子所放数字. #include<cst ...

  3. POJ2676 – Sudoku(数独)—DFS

    Sudoku Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 24081   Accepted: 11242   Specia ...

  4. Sudoku 数独游戏

    #include<iostream> using namespace std; bool heng(int **sudo, int a, int b, int value) { bool ...

  5. POJ Sudoku 数独填数 DFS

    题目链接:Sudoku Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 18105   Accepted: 8772   Sp ...

  6. leetcode 37. Sudoku Solver 36. Valid Sudoku 数独问题

    三星机试也考了类似的题目,只不过是要针对给出的数独修改其中三个错误数字,总过10个测试用例只过了3个与世界500强无缘了 36. Valid Sudoku Determine if a Sudoku ...

  7. valid sudoku(数独)

    Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku board could be ...

  8. POJ 2676 Sudoku (数独 DFS)

      Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 14368   Accepted: 7102   Special Judg ...

  9. POJ - 2676 Sudoku 数独游戏 dfs神奇的反搜

    Sudoku Sudoku is a very simple task. A square table with 9 rows and 9 columns is divided to 9 smalle ...

  10. 2015南阳CCPC H - Sudoku 数独

    H - Sudoku Description Yi Sima was one of the best counselors of Cao Cao. He likes to play a funny g ...

随机推荐

  1. 用,隔开sql临时表

    IF OBJECT_ID('[kkd].[proc_kkd_GetAutoExamineBid]') IS NOT NULL BEGIN DROP PROC [kkd].[proc_kkd_GetAu ...

  2. List集合实战总结

    //构造被分隔的集合 List<object> list = new List<object>(); for (int i = 0; i <= 100; i++) { l ...

  3. 使用Android Studio开发J2SE项目方法

    0.前言 最近因为要为项目开发一个底层的Java应用,所以非常偶然的遇到了这样一个问题,过去Eclipse有Java Project而现在手头使用Android Studio并不能直接建立Java应用 ...

  4. 刀哥多线程笔记之gcd-02-block

    block 概念 block 是 C 语言的 是一种数据类型,可以当作参数传递 是一组预先准备好的代码,在需要的时候执行 动画 block 回顾 self.demoView.center = CGPo ...

  5. java中对象的序列化和反序列化

    [对象的序列化和反序列化 ] 1.定义:序列化--将对象写到一个输出流中.反序列化则是从一个输入流中读取一个对象.类中的成员必须是可序列化的,而且要实现Serializable接口,这样的类的对象才能 ...

  6. bash: 避免命令重复执行的简单脚本

    1. 根据命令生成md5做为文件名保存当前进程的pid2. 使用exec执行命令3. 如果再次执行, 使用ps -p检测上次pid是否有效, 如果是则exit 200.否则重复1.hadoop@ubu ...

  7. OpenStack:安装Neutron与provider network

    1. 安装(1)Install Networking services on a dedicated network node# apt-get install neutron-server neut ...

  8. 不靠谱的Paypal及海外网站

    昨天因为报名参加某个比赛,需要用到Paypal付款,整整折腾了我一个小时.我先是使用自己的银行储蓄卡,到最后一步需要银行确认,提示我需要安装个插件才能输入密码.安装完插件后需要重启浏览器,整个流程又要 ...

  9. EntityFramwork(2Database First) 源地址https://msdn.microsoft.com/zh-cn/data/jj193542

    必备条件 要完成本演练,需要安装 Visual Studio 2010 或 Visual Studio 2012. 如果使用的是 Visual Studio 2010,还需要安装 NuGet.     ...

  10. firebreath 在谷歌和火狐浏览器下的调试 以及打包

    在寻找插件开发资料的过程中找到了一个开发浏览器插件的开源项目——firebreath firebreath的安装以及测试我就不再叙述了,可以参考大神的文章 . http://www.blogjava. ...