上交三月月赛[SJTU] 1106 sudoku
题目大意:给出一道数独题,判断该数独是否有解且有唯一解。
解题思路:
由前几题的难度得,此题的难度不会太过分,所以简单暴力就可以了,40ms用时一本满足。
简单地讲一下具体的实现,从左上开始从左到右从上到下一格一格枚举过去,枚举当前格子的数字时,判断一下这个数字能不能用就行了(判断是否在该行,该列,该区域出现过),全部填满时就找到了一个解,找到第二个解的时候停止搜索即可。
关于判断某个数字在当前区域是否用过,比较方便的方法是,事先算好p[i][j],用来记录第i行第j格属于哪一列,哪一行,哪一区域,这样在写dfs时会方便很多。
代码:
/* 被注释掉的代码都是用来调试的,取消注释后可以用来查看程序运行过程以便调试。 */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> using namespace std; #define FOR(i,a,b) for(int i=a;i<=b;i++) #define MST(a,b) memset(a,b,sizeof(a)) #define MAXL 10 int error;//用于发现不合理时终止程序 int g[MAXL][MAXL];//存放数组初始状态 int p1[MAXL][MAXL],p2[MAXL][MAXL],p3[MAXL][MAXL];//分别记录(i,j)所对应的行,列,区域 int b1[MAXL][MAXL],b2[MAXL][MAXL],b3[MAXL][MAXL];//记录编号为i的行,列,区域的数字使用情况 void init()//读入部分 { error=0; FOR(i,1,9)FOR(j,1,9)scanf("%d",&g[i][j]); MST(b1,0); MST(b2,0); MST(b3,0); FOR(i,1,9)FOR(j,1,9)if(g[i][j]) { int p=p1[i][j],x=g[i][j]; if(b1[p][x])error=1; b1[p][x]=1; p=p2[i][j]; if(b2[p][x])error=1; b2[p][x]=1; p=p3[i][j]; if(b3[p][x])error=1; b3[p][x]=1; } } int g2[MAXL][MAXL];//调试时用的数组,可无视 int tot;//记录解的个数 void dfs(int x,int y) { if(x==10)//dfs到第10行意味着已经全部填满 { tot++; if(tot>1)error=1;//若发现第二个解则终止程序 /*FOR(i,1,9) { FOR(j,1,9)printf("%d ",g2[i][j]+g[i][j]); printf("\n"); } printf("\n");*/ return; } int xt=x,yt=y+1;//计算下一个 if(yt>9){xt++;yt=1;} if(g[x][y]){dfs(xt,yt);return;}//若该格已有数字则无需尝试,直接进入下一格 int c1=p1[x][y],c2=p2[x][y],c3=p3[x][y];//记录当前格所在的行,列,区域的编号 FOR(i,1,9) if(b1[c1][i]+b2[c2][i]+b3[c3][i]==0)//是否在当前行,列,区域都未使用 { b1[c1][i]=1; b2[c2][i]=1; b3[c3][i]=1; //g2[x][y]=i; dfs(xt,yt);//进入下一格继续尝试 //g2[x][y]=0; if(error)return; b1[c1][i]=0; b2[c2][i]=0; b3[c3][i]=0; } } void work()//计算部分g2和输出error什么的请无视 { MST(g2,0); tot=0; dfs(1,1); //if(error)printf("error"); if(tot==0 || error)printf("No\n"); else printf("Yes\n"); } int main() { freopen("in.txt","r",stdin);//文件输入以便调试 //freopen("out.txt","w",stdout); FOR(i,1,9)FOR(j,1,9)p1[i][j]=i; FOR(i,1,9)FOR(j,1,9)p2[i][j]=j; FOR(i,1,9)FOR(j,1,9)p3[i][j]=((i-1)/3)*3+((j-1)/3)+1;//预处理i,j所在区域 /*FOR(i,1,9) { FOR(j,1,9)printf("%d ",p3[i][j]); printf("\n"); }*/ //上面的代码用来检查预处理时有无算错,下面开始是正片 int nn; scanf("%d",&nn); FOR(ii,1,nn) { init(); if (error){printf("No\n");continue;} work(); } }