poj(2676)——Sudoku
来源:互联网 发布:刻光盘软件那个好 编辑:程序博客网 时间:2024/05/22 15:25
在HDU上做这道题,感觉挺难的但是也挺好的dfs题,认为是一道dfs进阶题目(大神请忽略),在网上搜到一个不错的题解,我又详细的补充了一下注释,这样就很全面了:
1103000509002109400000704000300502006060000050700803004000401000009205800804000107
143628579572139468986754231391542786468917352725863914237481695619275843854396127
题目大意:
给你一个数独,让你填数:
1.每行的九个数字互不相同;
2.每列的九个数字各不相同;
3.被分成的3*3的小矩阵中的九个数字互不相同;
输出完成后的数表,由题意及数独规则知,一定有且只有一个数表。
算法分析:
DFS。。失败了回溯~
用三个数组进行标记每行、每列、每个子网格已用的数字,用于剪枝
bool row[10][10]; //row[i][x] 标记在第i行中数字x是否出现了
bool col[10][10]; //col[j][y] 标记在第j列中数字y是否出现了
bool small[10][10]; //small[k][x] 标记在第k个3*3子格中数字z是否出现了
row 和 col的标记比较好处理,关键是找出small子网格的序号与 行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子格中数字z是否出现了
AC代码及注释:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
bool row[10][10];//row[i][x] 标记在第i行中数字x是否出现了
bool col[10][10];//col[j][y] 标记在第j列中数字y是否出现了
int map[10][10];
bool small[10][10];//small[k][z] 标记在第k个3*3子格中数字z是否出现了
int f(int x,int y)//判断(x,y)属于哪个3*3子格
{
return 3*((x-1)/3)+(y-1)/3+1;
}
void init()//判断row[i][x],col[j][y],small[k][z]中的数字是否出现并且给map赋值;如果该数字出现,则标记为1,否则为2
{
int i,j;
char ch;
memset(row,0,sizeof(row));
memset(col,0,sizeof(col));
memset(small,0,sizeof(small));
for(i=1; i<=9; i++)
{
for(j=1; j<=9; j++)
{
scanf("%c",&ch);
map[i][j]=ch-'0';
if(map[i][j])
{
int k;
k=f(i,j);
row[i][map[i][j]]=1;
col[j][map[i][j]]=1;
small[k][map[i][j]]=1;
}
}
getchar();//getchar()用来接收输入时换行的回车,因为回车也是一个字符
}
}
int dfs(int x,int y)//搜索
{
if(x==10)//只搜索完前九行就ok,第十行就自动确定了
return 1;
int flag=0;
if(map[x][y])//如果(x,y)处数字不为零
{
if(y==9)
flag=dfs(x+1,1);//如果搜索到某一行的第9列,然后搜索下一行的第1列
else
flag=dfs(x,y+1);//否则,继续搜索下一列
if(flag)
return 1;
else
return 0;
}
else//如果(x,y)处数字为零
{
int k=f(x,y);//(x,y)属于哪一个3*3子格
for(int i=1; i<=9; i++)
if(!row[x][i] && !col[y][i] && !small[k][i])
{
map[x][y]=i;
row[x][i]=1;
col[y][i]=1;
small[k][i]=1;
if(y==9)
flag=dfs(x+1,1);
else
flag=dfs(x,y+1);
if(!flag)//回溯
{
map[x][y]=0;
row[x][i]=0;
col[y][i]=0;
small[k][i]=0;
}
else
return 1;
}
}
return 0;
}
int main()
{
int t;
scanf("%d",&t);
getchar();//getchar()用来接收输入时换行的回车,因为回车也是一个字符
while(t--)
{
init();//判断row[i][x],col[j][y],small[k][z]中的数字是否出现;如果该数字出现,则标记为1,否则为2
dfs(1,1);//从(1,1)开始搜索
for(int i=1; i<=9; i++)
{
for(int j=1; j<=9; j++)
printf("%d",map[i][j]);
printf("\n");
}
}
return 0;
}
还有,我自己的代码在codeblock上可以运行,样例可以通过,但提交上老是显示runtime error,有没有大神帮我看看哪出错了:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
struct point{
int x,y;
}pur[100];
int map[15][15],flag,num;
int check(int k,int cur)
{
int i,j,x,y;
for(i=0;i<9;i++)
if(map[pur[cur].x][i]==k||map[i][pur[cur].y]==k)return 0;//查找每一横行和每一竖列
x=(pur[cur].x/3)*3;
y=(pur[cur].y/3)*3;
for(i=x;i<x+3;i++)
for(j=y;j<y+3;j++)
if(map[i][j]==k)return 0;//查找当前九宫格
return 1;
}
void DFS(int step)
{
int i,j;
if(step==num){
for(i=0;i<9;i++)
{
for(j=0;j<8;j++)
printf("%d",map[i][j]);
printf("%d\n",map[i][8]);
}
flag=1;
return;
}
else{
for(i=1;i<=9;i++)
{
if(check(i,step)&&!flag)
{
map[pur[step].x][pur[step].y]=i;
DFS(step+1);
map[pur[step].x][pur[step].y]=0;
}
}
}
return;
}
int main()
{
int i,j,cas=0;
char s[15][15];
int d;
scanf("%d",d);
for(int h=0;h<d;h++)
{memset(s,0,sizeof(s));
memset(pur,0,sizeof(pur));
memset(map,0,sizeof(map));
for(i=0;i<9;i++)
for(j=0;j<9;j++)
{cin>>s[i][j];
if(s[i][j]=='0'){pur[num].x=i;pur[num].y=j;num++;map[i][j]=0;}
else map[i][j]=s[i][j]-'0';
}
flag=0;
if(cas++) cout<<endl;
DFS(0);
}
return 0;
}
- POJ 2676—Sudoku
- poj(2676)——Sudoku
- poj(2676)——Sudoku
- poj(2676)——Sudoku
- poj 2676 Sudoku
- POJ 2676 Sudoku
- POJ 2676 Sudoku dfs
- Poj 2676 Sudoku
- POJ 2676 Sudoku [暴搜]
- POJ 2676 Sudoku
- POJ 2676 Sudoku
- POJ 2676 Sudoku
- POJ 2676 Sudoku
- POJ 2676 Sudoku
- POJ-2676-Sudoku
- poj 2676 Sudoku
- POJ 2676 Sudoku
- POJ 2676 Sudoku
- 响应式的车牌登记页面
- IntelliJ Idea 2017 免费激活方法
- 数组
- python打飞机小程序
- java8 LocalDate 类型 json 解析 日期格式处理
- poj(2676)——Sudoku
- new和delete表达式
- 通过修改MAC地址来解决TeamViewer的试用期到期问题
- .NET CORE GUID字符串的几种格式化
- maven配置阿里云镜像文件/阿里云中央仓库
- C#遍历List并删除元素的方法概述
- 分布式锁zookeeper
- 常见的数据结构小总结
- 冒泡排序方法浅谈