这题就是一个裸的数独求解,不卡内存,也不卡时间,要求会基本的Coding(编码),和暴力求解问题的思想,或者说穷举,说到底就是搜索
要了解到数独可行解一定满足所在行列和子九宫格的元素唯一性,满足当前集合的元素的唯一性,把集合填满就是解决了问题。
搜索要注意状态数和每一个状态要进行的操作的复杂度,所以不能对每一个点重新检查它所在行列九宫格的元素集合,这样的复杂度过不去,因为391MS*27 > 1S
注意到一个元素的进出,所在行列子格的元素集合状态也会发生变化,所以可以用三个集合描述三个状态,即当前行,列和子格的已出现的元素.
然后暴搜过去就行了
还有一个问题,就是如果你把输出写在搜索的有效解的位置,可能会OLE,搜索结束的时候再输出便好。(这样可以不挂ans数组,因为我我回溯没有复原数组)
还有一个问题,就是如果题目是这样的,如果有多种解的时候输出more than one ans! 这时候该怎么优化呢,怎么剪枝
//Memory Time //176K 391MS //author: xiecong //date: 15.9.8 #include <iostream> #include <cstdio> #include <cstring> using namespace std; int sudo[10][10]; int ans[10][10]; bool ok; bool rflag[10][10];//row bool lflag[10][10];//lie bool sflag[10][10];//sub void dfs(int r, int pos) { if(ok) return; if(r==9) { memcpy(ans,sudo,sizeof sudo); ok = true; return ; } if(sudo[r][pos]==0) { int sub = r/3*3+pos/3; for (int tp=1;tp<10;tp++) { if(rflag[r ][tp]||lflag[pos][tp]||sflag[sub][tp]) continue; //if(ok) break; rflag[r ][tp] = true; lflag[pos][tp] = true; sflag[sub][tp] = true; sudo[r][pos] = tp; if(pos==8) dfs(r+1,0); else dfs(r,pos+1); //if(ok) continue; sudo[r][pos] = 0; rflag[r ][tp] = false; lflag[pos][tp] = false; sflag[sub][tp] = false; } }else { if(pos==8) dfs(r+1,0); else dfs(r,pos+1); } } int main() { #ifndef ONLINE_JUDGE freopen("in","r",stdin); #endif int Case; for (scanf("%d", &Case); Case; Case--) { memset(rflag,0,sizeof rflag); memset(lflag,0,sizeof rflag); memset(sflag,0,sizeof rflag); for (int i= 0; i< 9; i++) for (int j= 0; j< 9; j++){ scanf("%1d",sudo[i]+j); int tmp = sudo[i][j]; rflag[i ][tmp] = true; lflag[j][tmp] = true; sflag[i/3*3+j/3][tmp] = true; } dfs(0, ok=0); for (int i= 0; i< 9; i++) { for (int j= 0; j< 9; j++) printf("%d", ans[i][j]); putchar('\n'); } } return 0; }