php數獨
A. 數獨的技巧
單向掃看法:在第一個例子中,我們注意看一下第2宮。
我們知道,每個宮內必須包含數字9,第1宮以及第3宮中都包含數字9,並且第1宮的9位於第3行。
第3宮的9位於第2行,這也就意味著第2宮的9不能在第2行和第3行,所有第2宮的9隻能放置在第2宮第1行的空格內。
2.雙向掃看法:同樣的技巧也可以擴展到相互垂直的行與列中。讓我們想一下第3宮中1應該放在哪裡。在這個例子中,第1行以及第2行已經有1了,那麼第3宮中只有底部的倆個空格可以填1。不過,方格g4已經有1了,所有第g列不能再有1。
所以i3是該宮唯一符合條件填上數字1的地方。
3.尋找候選法:通常地,一個方格只能有一個數字的可能性,因為剩下的其他8個數字都已經被相關的行列宮所排除了。我們看一下下面例子中b4這個方格。b4所在的宮中已經存在了數字3,4,7,8,1和6位於同一行,5和9位於同一列,排除上述所有數字,b4隻能填上2。
4數字排除法:排除法是一個相對繁雜的尋找數字的方法。我們可以從c8中的1間接推出e7和e9必須包含數字1,不管這個1在哪個方格,我們可以確認的是,第e列的數字1肯定在第8宮內,所以第2宮內中間這一列就不可能存在數字1。因此,第2宮的數字一必須填在d2處。
B. 求數獨源碼
沒試過
#include < stdio.h >
#include < stdlib.h >
int sudoku[81] ; // 數獨題目陣列
int tempNum[81] ; // 上一次填數位置
int tempSp= 0 ; // 上一次填數位置指標
int startH[81] ; // 列位置的起點
int startV[81] ; // 行位置的起點
int startB[81] ; // 九宮格位置的起點
int addH[9] ; // 列位置的加值
int addV[9] ; // 行位置的加值
int addB[9] ; // 九宮格位置的加值
int main(int argc, char *argv[]) {
int j ;
if(argc>1) for(j=0; j<81; j++) sudoku[j]= argv[1][j]-'0' ;
else exit(0) ;
printf( "----------\n");
printSudoku(sudoku) ;
init() ; // 參數設定
tryAns() ; // 測試求解
printf( "----------\n");
printSudoku(sudoku) ;
printf( "----------\n");
}
int init() {
// 參數設定(設定這些參數之後,無論檢查行、列、九宮格都方便多了)
int i ;
for(i=0; i<81; i++) {
startH[i]= i/9* 9 ; // 列位置的起點
startV[i]= i% 9 ; // 行位置的起點
startB[i]= ((i/9)/3)*27+ ((i%9)/3)*3 ; // 九宮格位置的起點
}
for(i=0; i<9; i++) {
addH[i]= i ; // 列位置的加值
addV[i]= i*9 ; // 行位置的加值
addB[i]= (i/3)*9+ (i%3) ; // 九宮格位置的加值
}
}
int printSudoku(int *prn) {
// 印出數獨題目(陣列內容)
int i ;
for(i=0; i<81; i++) {
printf( "%2d", prn[i]);
if(i%9==8) printf("\n");
}
}
int tryAns() {
// 測試求解
int sp=getNextBlank(-1) ; // 取得第一個空白的位置開始填入數字
do {
sudoku[sp]++ ; // 將本位置數字加 1
if(sudoku[sp]>9) { // 如果本位置的數字已大於 9 時則回到上一個位置繼續測試
sudoku[sp]= 0 ;
sp= pop() ;
} else {
if(check(sp)==0) { // 如果同行、列、九宮格都沒有相同的數字,則到下一個空白處繼續
push(sp) ; // 當然,如果發現有相同的數字時,就需把原位置的數字加 1(所以本處什麼都不做)
sp= getNextBlank(sp) ;
}
}
} while(sp>=0 && sp<81) ;
}
int getNextBlank(int sp) {
// 取得下一個空白的位置
do {
sp++ ;
} while(sp<81 && sudoku[sp]>0) ;
return(sp) ;
}
int check(int sp) {
// 檢查同行、列、九宮格有沒有相同的數字,若有傳回 1
int fg= 0 ;
if(!fg) fg= check1(sp, startH[sp], addH) ; // 檢查同列有沒有相同的數字
if(!fg) fg= check1(sp, startV[sp], addV) ; // 檢查同行有沒有相同的數字
if(!fg) fg= check1(sp, startB[sp], addB) ; // 檢查同九宮格有沒有相同的數字
return(fg) ;
}
int check1(int sp, int start, int *addnum) {
// 檢查指定的行、列、九宮格有沒有相同的數字,若有傳回 1
int fg= 0, i, sp1 ;
for(i=0; i<9; i++) {
sp1= start+ addnum[i] ;
if(sp!=sp1 && sudoku[sp]==sudoku[sp1]) fg++ ;
}
return(fg) ;
}
int push(int sp) {
// 將指定的位置放入堆疊中
tempNum[tempSp++]= sp ;
}
int pop() {
// 取出堆疊中的上一個位置
if(tempSp<0) return(-1) ;
else return(tempNum[--tempSp]) ;
}
參考資料:http://bbs.bc-cn.net/viewthread.php?tid=189678&page=1 演算法如下,先構造一個9*9的結構體數組,表示棋盤數據0表示空白未知,結構體中每個元素
包含一個1-9的數組作為備選數字.
構建好一個棋盤之後依次對每個空白位置進行備選數字中進行刪除.當前已經填寫的數字就全部刪除
如果只剩下一個備選數字就將該備選數字填寫到棋盤數據中.該演算法在AI這個函數中實現.
當無法用AI演算法推出結果的時候就進行回朔法,見找到有兩個備選數字的元素,選取其中一個,
繼續往下填寫,直到全部填寫上去(結束),或者無法繼續填寫(某個空白位置沒有備選元素).
如果無法繼續填寫下去就表示最初選擇的那個數據是錯誤的,直接填寫另外一個數據到棋盤上.
該演算法在AdvanceAI中體現出來
如此下去就能夠填寫出棋盤中的所有元素.
#include <cstdio>
#include <vector>
#include <algorithm>
enum{SIZE=81};
unsigned int Data[SIZE]={//未解棋盤數據
0 , 9 , 0 , 0 , 6 , 0 , 5 , 4 , 8 ,
4 , 0 , 3 , 0 , 8 , 0 , 9 , 0 , 0 ,
8 , 6 , 5 , 4 , 7 , 9 , 1 , 2 , 3 ,
0 , 5 , 6 , 3 , 9 , 0 , 4 , 0 , 1 ,
1 , 4 , 0 , 0 , 5 , 0 , 2 , 0 , 0 ,
0 , 0 , 0 , 0 , 4 , 1 , 0 , 0 , 0 ,
0 , 0 , 0 , 8 , 2 , 0 , 6 , 1 , 0 ,
0 , 0 , 0 , 0 , 3 , 0 , 0 , 0 , 4 ,
5 , 8 , 0 , 9 , 1 , 0 , 0 , 0 , 0 };
const int temp[9] = { 1 , 2 , 3, 4, 5, 6, 7, 8, 9};
struct Item
{
int data;
std::vector<int> other;
Item():data(0),other(temp,temp+9){}
inline bool operator==(int x)
{
return x==data?true:false;
}
inline Item& operator=(const Item& src)
{
data = src.data ;
other = src.other;
return (*this);
};
inline Item& operator=(int x){
data = x ;
std::(temp,temp+sizeof(temp)/sizeof(temp[0]) , other.begin());
return (*this);
};
void test(size_t x ){
if( other.size() == 2 )
data = other[x];
}
inline operator int(){return data;}
};
struct GroupInfo{
const int Group1,Group2,Group3;
GroupInfo(int g1,int g2,int g3):Group1(g1),Group2(g2),Group3(g3){}
inline bool operator==(GroupInfo& src){
return ((Group1|Group2|Group3)&(src.Group1|src.Group2|src.Group3))?true:false;
}
};
GroupInfo Group[SIZE]={
GroupInfo( 1<<1 , 1<<10 , 1<<19) ,GroupInfo( 1<<1 , 1<<11 , 1<<19) ,GroupInfo( 1<<1 , 1<<12 , 1<<19) ,GroupInfo( 1<<1 , 1<<13 , 1<<20) ,GroupInfo( 1<<1 , 1<<14 , 1<<20) ,GroupInfo( 1<<1 , 1<<15 , 1<<20) ,GroupInfo( 1<<1 , 1<<16 , 1<<21) ,GroupInfo( 1<<1 , 1<<17 , 1<<21) ,GroupInfo( 1<<1 , 1<<18 , 1<<21) ,
GroupInfo( 1<<2 , 1<<10 , 1<<19) ,GroupInfo( 1<<2 , 1<<11 , 1<<19) ,GroupInfo( 1<<2 , 1<<12 , 1<<19) ,GroupInfo( 1<<2 , 1<<13 , 1<<20) ,GroupInfo( 1<<2 , 1<<14 , 1<<20) ,GroupInfo( 1<<2 , 1<<15 , 1<<20) ,GroupInfo( 1<<2 , 1<<16 , 1<<21) ,GroupInfo( 1<<2 , 1<<17 , 1<<21) ,GroupInfo( 1<<2 , 1<<18 , 1<<21) ,
GroupInfo( 1<<3 , 1<<10 , 1<<19) ,GroupInfo( 1<<3 , 1<<11 , 1<<19) ,GroupInfo( 1<<3 , 1<<12 , 1<<19) ,GroupInfo( 1<<3 , 1<<13 , 1<<20) ,GroupInfo( 1<<3 , 1<<14 , 1<<20) ,GroupInfo( 1<<3 , 1<<15 , 1<<20) ,GroupInfo( 1<<3 , 1<<16 , 1<<21) ,GroupInfo( 1<<3 , 1<<17 , 1<<21) ,GroupInfo( 1<<3 , 1<<18 , 1<<21) ,
GroupInfo( 1<<4 , 1<<10 , 1<<22) ,GroupInfo( 1<<4 , 1<<11 , 1<<22) ,GroupInfo( 1<<4 , 1<<12 , 1<<22) ,GroupInfo( 1<<4 , 1<<13 , 1<<23) ,GroupInfo( 1<<4 , 1<<14 , 1<<23) ,GroupInfo( 1<<4 , 1<<15 , 1<<23) ,GroupInfo( 1<<4 , 1<<16 , 1<<24) ,GroupInfo( 1<<4 , 1<<17 , 1<<24) ,GroupInfo( 1<<4 , 1<<18 , 1<<24) ,
GroupInfo( 1<<5 , 1<<10 , 1<<22) ,GroupInfo( 1<<5 , 1<<11 , 1<<22) ,GroupInfo( 1<<5 , 1<<12 , 1<<22) ,GroupInfo( 1<<5 , 1<<13 , 1<<23) ,GroupInfo( 1<<5 , 1<<14 , 1<<23) ,GroupInfo( 1<<5 , 1<<15 , 1<<23) ,GroupInfo( 1<<5 , 1<<16 , 1<<24) ,GroupInfo( 1<<5 , 1<<17 , 1<<24) ,GroupInfo( 1<<5 , 1<<18 , 1<<24) ,
GroupInfo( 1<<6 , 1<<10 , 1<<22) ,GroupInfo( 1<<6 , 1<<11 , 1<<22) ,GroupInfo( 1<<6 , 1<<12 , 1<<22) ,GroupInfo( 1<<6 , 1<<13 , 1<<23) ,GroupInfo( 1<<6 , 1<<14 , 1<<23) ,GroupInfo( 1<<6 , 1<<15 , 1<<23) ,GroupInfo( 1<<6 , 1<<16 , 1<<24) ,GroupInfo( 1<<6 , 1<<17 , 1<<24) ,GroupInfo( 1<<6 , 1<<18 , 1<<24) ,
GroupInfo( 1<<7 , 1<<10 , 1<<25) ,GroupInfo( 1<<7 , 1<<11 , 1<<25) ,GroupInfo( 1<<7 , 1<<12 , 1<<25) ,GroupInfo( 1<<7 , 1<<13 , 1<<26) ,GroupInfo( 1<<7 , 1<<14 , 1<<26) ,GroupInfo( 1<<7 , 1<<15 , 1<<26) ,GroupInfo( 1<<7 , 1<<16 , 1<<27) ,GroupInfo( 1<<7 , 1<<17 , 1<<27) ,GroupInfo( 1<<7 , 1<<18 , 1<<27) ,
GroupInfo( 1<<8 , 1<<10 , 1<<25) ,GroupInfo( 1<<8 , 1<<11 , 1<<25) ,GroupInfo( 1<<8 , 1<<12 , 1<<25) ,GroupInfo( 1<<8 , 1<<13 , 1<<26) ,GroupInfo( 1<<8 , 1<<14 , 1<<26) ,GroupInfo( 1<<8 , 1<<15 , 1<<26) ,GroupInfo( 1<<8 , 1<<16 , 1<<27) ,GroupInfo( 1<<8 , 1<<17 , 1<<27) ,GroupInfo( 1<<8 , 1<<18 , 1<<27) ,
GroupInfo( 1<<9 , 1<<10 , 1<<25) ,GroupInfo( 1<<9 , 1<<11 , 1<<25) ,GroupInfo( 1<<9 , 1<<12 , 1<<25) ,GroupInfo( 1<<9 , 1<<13 , 1<<26) ,GroupInfo( 1<<9 , 1<<14 , 1<<26) ,GroupInfo( 1<<9 , 1<<15 , 1<<26) ,GroupInfo( 1<<9 , 1<<16 , 1<<27) ,GroupInfo( 1<<9 , 1<<17 , 1<<27) ,GroupInfo( 1<<9 , 1<<18 , 1<<27)
};
bool AI(std::vector<Item>& game)
{
bool bMoveflag = false;
for(size_t x = 0 ; x < game.size() ; ++x ){
if( 0 != game[x].data ){//依次檢查每個位置
game[x].other.resize(0);
continue;
}
//當前位置沒有數字
std::vector<int> vTemp;
for(int i = 0 ; i < 81 ; ++i )
if( Group[x]==Group[i] )
vTemp.push_back ( game[i].data );
;
vTemp.erase( std::remove(vTemp.begin(),vTemp.end() , 0 ) , vTemp.end() );
//移除同組已經出現的數字
for(std::vector<int>::iterator Iter = vTemp.begin() ; Iter !=vTemp.end() ; ++ Iter )
std::replace(game[x].other.begin() , game[x].other.end() , (*Iter) , 0 );
game[x].other.erase( std::remove(game[x].other.begin(),game[x].other.end() , 0 ) ,game[x].other.end() );
if( ( 1 == game[x].other.size())&&( 0 != game[x].other[0] ) ){
game[x].data = game[x].other[0];
bMoveflag = true;
}
}
return bMoveflag;
}
struct OtherIs2Opt{
bool operator()(Item& item)
{return ( item.other.size()==2)?true:false;}
};
struct testBackOpt
{
bool bBack;
testBackOpt():bBack(false){}
void operator()(Item& item)
{
if( ( item.data==0)&&(item.other.size()==0) )
bBack = true;
}
};
bool AdvanceAI(std::vector<Item>& game)
{
std::vector<Item> Back = game;
std::vector<Item>::iterator iItem = std::find_if( Back.begin() , Back.end() , OtherIs2Opt() );
if( iItem != Back.end() ){
for(size_t i = 0 ; i < (*iItem).other.size() ; ++i ){
(*iItem).test( i );
for( ; AI( Back ) ;);
if( std::for_each( Back.begin() , Back.end() , testBackOpt() ).bBack ){//是否結束回滾
Back = game;
iItem = std::find_if( Back.begin() , Back.end() , OtherIs2Opt() );
continue;
}
if( std::count( Back.begin() , Back.end() , 0 ) ){//判斷是否結束
if( AdvanceAI( Back ) ){//沒有結束,繼續下一步遞歸
game = Back ;
return true;
}
Back = game;
iItem = std::find_if( Back.begin() , Back.end() , OtherIs2Opt() );
continue;
}else{//back為結果
game = Back ;
return true;
}
}
}
return false;
}
int main(int argc, char* argv[])
{//初始化棋盤
std::vector<Item> game(SIZE);
std::(Data,Data+SIZE , game.begin() );
for( ; AI( game ) ;);
if( std::count( game.begin() , game.end() , 0 ) ){
if( !AdvanceAI( game ) )
printf("沒解出來 ");
}
for(int x = 0 ; x < 81 ; ++x ){
printf(" %d",game[x].data );
if( 0 == (x +1)% 9 )
printf(" ");
}
return 0;演算法如下,先構造一個9*9的結構體數組,表示棋盤數據0表示空白未知,結構體中每個元素
包含一個1-9的數組作為備選數字.
構建好一個棋盤之後依次對每個空白位置進行備選數字中進行刪除.當前已經填寫的數字就全部刪除
如果只剩下一個備選數字就將該備選數字填寫到棋盤數據中.該演算法在AI這個函數中實現.
當無法用AI演算法推出結果的時候就進行回朔法,見找到有兩個備選數字的元素,選取其中一個,
繼續往下填寫,直到全部填寫上去(結束),或者無法繼續填寫(某個空白位置沒有備選元素).
如果無法繼續填寫下去就表示最初選擇的那個數據是錯誤的,直接填寫另外一個數據到棋盤上.
該演算法在AdvanceAI中體現出來
如此下去就能夠填寫出棋盤中的所有元素.
#include <cstdio>
#include <vector>
#include <algorithm>
enum{SIZE=81};
unsigned int Data[SIZE]={//未解棋盤數據
0 , 9 , 0 , 0 , 6 , 0 , 5 , 4 , 8 ,
4 , 0 , 3 , 0 , 8 , 0 , 9 , 0 , 0 ,
8 , 6 , 5 , 4 , 7 , 9 , 1 , 2 , 3 ,
0 , 5 , 6 , 3 , 9 , 0 , 4 , 0 , 1 ,
1 , 4 , 0 , 0 , 5 , 0 , 2 , 0 , 0 ,
0 , 0 , 0 , 0 , 4 , 1 , 0 , 0 , 0 ,
0 , 0 , 0 , 8 , 2 , 0 , 6 , 1 , 0 ,
0 , 0 , 0 , 0 , 3 , 0 , 0 , 0 , 4 ,
5 , 8 , 0 , 9 , 1 , 0 , 0 , 0 , 0 };
const int temp[9] = { 1 , 2 , 3, 4, 5, 6, 7, 8, 9};
struct Item
{
int data;
std::vector<int> other;
Item():data(0),other(temp,temp+9){}
inline bool operator==(int x)
{
return x==data?true:false;
}
inline Item& operator=(const Item& src)
{
data = src.data ;
other = src.other;
return (*this);
};
inline Item& operator=(int x){
data = x ;
std::(temp,temp+sizeof(temp)/sizeof(temp[0]) , other.begin());
return (*this);
};
void test(size_t x ){
if( other.size() == 2 )
data = other[x];
}
inline operator int(){return data;}
};
struct GroupInfo{
const int Group1,Group2,Group3;
GroupInfo(int g1,int g2,int g3):Group1(g1),Group2(g2),Group3(g3){}
inline bool operator==(GroupInfo& src){
return ((Group1|Group2|Group3)&(src.Group1|src.Group2|src.Group3))?true:false;
}
};
GroupInfo Group[SIZE]={
GroupInfo( 1<<1 , 1<<10 , 1<<19) ,GroupInfo( 1<<1 , 1<<11 , 1<<19) ,GroupInfo( 1<<1 , 1<<12 , 1<<19) ,GroupInfo( 1<<1 , 1<<13 , 1<<20) ,GroupInfo( 1<<1 , 1<<14 , 1<<20) ,GroupInfo( 1<<1 , 1<<15 , 1<<20) ,GroupInfo( 1<<1 , 1<<16 , 1<<21) ,GroupInfo( 1<<1 , 1<<17 , 1<<21) ,GroupInfo( 1<<1 , 1<<18 , 1<<21) ,
GroupInfo( 1<<2 , 1<<10 , 1<<19) ,GroupInfo( 1<<2 , 1<<11 , 1<<19) ,GroupInfo( 1<<2 , 1<<12 , 1<<19) ,GroupInfo( 1<<2 , 1<<13 , 1<<20) ,GroupInfo( 1<<2 , 1<<14 , 1<<20) ,GroupInfo( 1<<2 , 1<<15 , 1<<20) ,GroupInfo( 1<<2 , 1<<16 , 1<<21) ,GroupInfo( 1<<2 , 1<<17 , 1<<21) ,GroupInfo( 1<<2 , 1<<18 , 1<<21) ,
GroupInfo( 1<<3 , 1<<10 , 1<<19) ,GroupInfo( 1<<3 , 1<<11 , 1<<19) ,GroupInfo( 1<<3 , 1<<12 , 1<<19) ,GroupInfo( 1<<3 , 1<<13 , 1<<20) ,GroupInfo( 1<<3 , 1<<14 , 1<<20) ,GroupInfo( 1<<3 , 1<<15 , 1<<20) ,GroupInfo( 1<<3 , 1<<16 , 1<<21) ,GroupInfo( 1<<3 , 1<<17 , 1<<21) ,GroupInfo( 1<<3 , 1<<18 , 1<<21) ,
GroupInfo( 1<<4 , 1<<10 , 1<<22) ,GroupInfo( 1<<4 , 1<<11 , 1<<22) ,GroupInfo( 1<<4 , 1<<12 , 1<<22) ,GroupInfo( 1<<4 , 1<<13 , 1<<23) ,GroupInfo( 1<<4 , 1<<14 , 1<<23) ,GroupInfo( 1<<4 , 1<<15 , 1<<23) ,GroupInfo( 1<<4 , 1<<16 , 1<<24) ,GroupInfo( 1<<4 , 1<<17 , 1<<24) ,GroupInfo( 1<<4 , 1<<18 , 1<<24) ,
GroupInfo( 1<<5 , 1<<10 , 1<<22) ,GroupInfo( 1<<5 , 1<<11 , 1<<22) ,GroupInfo( 1<<5 , 1<<12 , 1<<22) ,GroupInfo( 1<<5 , 1<<13 , 1<<23) ,GroupInfo( 1<<5 , 1<<14 , 1<<23) ,GroupInfo( 1<<5 , 1<<15 , 1<<23) ,GroupInfo( 1<<5 , 1<<16 , 1<<24) ,GroupInfo( 1<<5 , 1<<17 , 1<<24) ,GroupInfo( 1<<5 , 1<<18 , 1<<24) ,
GroupInfo( 1<<6 , 1<<10 , 1<<22) ,GroupInfo( 1<<6 , 1<<11 , 1<<22) ,GroupInfo( 1<<6 , 1<<12 , 1<<22) ,GroupInfo( 1<<6 , 1<<13 , 1<<23) ,GroupInfo( 1<<6 , 1<<14 , 1<<23) ,GroupInfo( 1<<6 , 1<<15 , 1<<23) ,GroupInfo( 1<<6 , 1<<16 , 1<<24) ,GroupInfo( 1<<6 , 1<<17 , 1<<24) ,GroupInfo( 1<<6 , 1<<18 , 1<<24) ,
GroupInfo( 1<<7 , 1<<10 , 1<<25) ,GroupInfo( 1<<7 , 1<<11 , 1<<25) ,GroupInfo( 1<<7 , 1<<12 , 1<<25) ,GroupInfo( 1<<7 , 1<<13 , 1<<26) ,GroupInfo( 1<<7 , 1<<14 , 1<<26) ,GroupInfo( 1<<7 , 1<<15 , 1<<26) ,GroupInfo( 1<<7 , 1<<16 , 1<<27) ,GroupInfo( 1<<7 , 1<<17 , 1<<27) ,GroupInfo( 1<<7 , 1<<18 , 1<<27) ,
GroupInfo( 1<<8 , 1<<10 , 1<<25) ,GroupInfo( 1<<8 , 1<<11 , 1<<25) ,GroupInfo( 1<<8 , 1<<12 , 1<<25) ,GroupInfo( 1<<8 , 1<<13 , 1<<26) ,GroupInfo( 1<<8 , 1<<14 , 1<<26) ,GroupInfo( 1<<8 , 1<<15 , 1<<26) ,GroupInfo( 1<<8 , 1<<16 , 1<<27) ,GroupInfo( 1<<8 , 1<<17 , 1<<27) ,GroupInfo( 1<<8 , 1<<18 , 1<<27) ,
GroupInfo( 1<<9 , 1<<10 , 1<<25) ,GroupInfo( 1<<9 , 1<<11 , 1<<25) ,GroupInfo( 1<<9 , 1<<12 , 1<<25) ,GroupInfo( 1<<9 , 1<<13 , 1<<26) ,GroupInfo( 1<<9 , 1<<14 , 1<<26) ,GroupInfo( 1<<9 , 1<<15 , 1<<26) ,GroupInfo( 1<<9 , 1<<16 , 1<<27) ,GroupInfo( 1<<9 , 1<<17 , 1<<27) ,GroupInfo( 1<<9 , 1<<18 , 1<<27)
};
bool AI(std::vector<Item>& game)
{
bool bMoveflag = false;
for(size_t x = 0 ; x < game.size() ; ++x ){
if( 0 != game[x].data ){//依次檢查每個位置
game[x].other.resize(0);
continue;
}
//當前位置沒有數字
std::vector<int> vTemp;
for(int i = 0 ; i < 81 ; ++i )
if( Group[x]==Group[i] )
vTemp.push_back ( game[i].data );
;
vTemp.erase( std::remove(vTemp.begin(),vTemp.end() , 0 ) , vTemp.end() );
//移除同組已經出現的數字
for(std::vector<int>::iterator Iter = vTemp.begin() ; Iter !=vTemp.end() ; ++ Iter )
std::replace(game[x].other.begin() , game[x].other.end() , (*Iter) , 0 );
game[x].other.erase( std::remove(game[x].other.begin(),game[x].other.end() , 0 ) ,game[x].other.end() );
if( ( 1 == game[x].other.size())&&( 0 != game[x].other[0] ) ){
game[x].data = game[x].other[0];
bMoveflag = true;
}
}
return bMoveflag;
}
struct OtherIs2Opt{
bool operator()(Item& item)
{return ( item.other.size()==2)?true:false;}
};
struct testBackOpt
{
bool bBack;
testBackOpt():bBack(false){}
void operator()(Item& item)
{
if( ( item.data==0)&&(item.other.size()==0) )
bBack = true;
}
};
bool AdvanceAI(std::vector<Item>& game)
{
std::vector<Item> Back = game;
std::vector<Item>::iterator iItem = std::find_if( Back.begin() , Back.end() , OtherIs2Opt() );
if( iItem != Back.end() ){
for(size_t i = 0 ; i < (*iItem).other.size() ; ++i ){
(*iItem).test( i );
for( ; AI( Back ) ;);
if( std::for_each( Back.begin() , Back.end() , testBackOpt() ).bBack ){//是否結束回滾
Back = game;
iItem = std::find_if( Back.begin() , Back.end() , OtherIs2Opt() );
continue;
}
if( std::count( Back.begin() , Back.end() , 0 ) ){//判斷是否結束
if( AdvanceAI( Back ) ){//沒有結束,繼續下一步遞歸
game = Back ;
return true;
}
Back = game;
iItem = std::find_if( Back.begin() , Back.end() , OtherIs2Opt() );
continue;
}else{//back為結果
game = Back ;
return true;
}
}
}
return false;
}
int main(int argc, char* argv[])
{//初始化棋盤
std::vector<Item> game(SIZE);
std::(Data,Data+SIZE , game.begin() );
for( ; AI( game ) ;);
if( std::count( game.begin() , game.end() , 0 ) ){
if( !AdvanceAI( game ) )
printf("沒解出來 ");
}
for(int x = 0 ; x < 81 ; ++x ){
printf(" %d",game[x].data );
if( 0 == (x +1)% 9 )
printf(" ");
}
return 0;
C. 數獨是什麼有什麼要求有什麼競賽
數獨是一種根據邏輯推理的益智游戲(運動)。國內起步較晚,國外已經盛行近20年。國內目前沒有特別大型或規范的比賽,不過有些小型的比賽。目前每年在北京有一次「全國賽」,是為去世錦賽產生名額用的。
樓上說的一些觀點我非常不贊同,什麼叫「不是需要長期需要努力鑽研的東西」,你懂數獨嗎,你了解多少,知道個標准數獨就跟不懂的人亂說,完全是誤人子弟,你不懂沒關系,不要出來裝懂好不好!
數獨每年在世界范圍內有一次世界數獨錦標賽,正好明天(2010年4月29日)美國時間下午開始舉行第五屆世界數獨錦標賽,這里是題目說明的網址http://www.worldpuzzle.org/wiki/index.php/Fifth_World_Sudoku_Championship/zh
你去看看什麼才是真正的數獨,就算你努力鑽研10年未必能達到目前國內頂尖選手的水平。
你所說的半個月搞定的數獨,是標准數獨中入門的幾種直觀解法,那些對於有點腦子的人來說半天就學會了,但把半天學習的運用非常熟練沒有1,2年的時間根本不可能,我說的是非常熟練。
況且現在在標准數獨的基礎上衍生出至少幾百種變形數獨,真正數獨比賽比的是綜合能力,當然標准數獨的基本功也是重要的考核項目之一。
樓主想學簡單的解法的話可以來網路數獨吧,置頂帖里有標准數獨的常用解法http://tieba..com/f?kz=510857623。
不過對於國內大多數人來說,還是當做休閑娛樂比較好,要想沖到高手的行列,需要花費大量的時間和精力,還需要有天生的資質,就算有些人再努力,到某個瓶頸也很難突破了。
數獨吧主:藍天skyhuner
D. 什麼是數獨
「數獨」(日語是すうどく,英文為Sudoku) 「數獨」(sudoku)一詞來自日語,意思是「單獨的數字」或「只出現一次的數字」。概括來說,它就是一種填數字游戲。但這一概念最初並非來自日本,而是源自拉丁方塊,它是十八世紀的瑞士數學家歐拉發明的。出生於1707年的歐拉被譽為有史以來最偉大的數學家之一。 歐拉從小就是一個數學天才,大學時他在神學院里攻讀古希伯來文,但卻連續13次獲得巴黎科學院的科學競賽的大獎。 1783年,歐拉發明了一個「拉丁方塊」,他將其稱為「一種新式魔方」,這就是數獨游戲的雛形。不過,當時歐拉的發明並沒有受到人們的重視。直到20世紀70年代,美國雜志才以「數字拼圖」的名稱將它重新推出。 1984年日本益智雜志Nikoli的員工金元信彥偶然看到了美國雜志上的這一游戲,認為可以用來吸引日本讀者,於是將其加以改良,並增加了難度,還為它取了新名字稱做「數獨」,結果推出後一炮而紅,讓出版商狂賺了一把。至今為止,該出版社已經推出了21本關於數獨的書籍,有一些上市後很快就出現了脫銷。 此外,出版商還授權軟體商開發了上百個數獨游戲軟體。供人們在網上購買。目前,日本共有5家數獨月刊,總發行量為66萬份。由於數獨在日本已經被注冊商標,其他競爭者只好使用其最初在美國的名字「數字拼圖」。 數獨游戲和傳統的填字游戲類似,但因為只使用1到9的數字,能夠跨越文字與文化疆域,所以被譽為是全球化時代的魔術方塊。 數獨游戲進入英國後,很多人立刻迷上了它。由於該游戲簡單易學,而且初級游戲並不難,所以很多人在工作休息時間以及乘車上班途中都是埋頭在報紙上狂玩數獨。更有人宣稱多玩數獨游戲可以延緩大腦衰老。 目前,英國涌現出了大量的關於數獨游戲的書籍,專門推廣此類游戲的網站也紛紛出現,人們可以從網上下載數獨軟體到電腦,也可以把軟體下載到手機上玩。 規則簡單易掌握 數獨的游戲規則很簡單,9x9個格子里,已有若干數字,其它宮位留白,玩家需要自己按照邏輯推敲出剩下的空格里是什麼數字,使得每一行與每一列都有1到9的數字,每個小九宮格里也有1到9的數字,並且一個數字在每個行列及每個小九宮格里都只能出現一次。 做這種游戲不需要填字謎那樣的語言技巧和文化知識,甚至也不需要復雜的數學能力。因為它根本不需要加減乘除運算。當然,你也千萬別小看它,並不是那麼容易被「制服」的。當你握筆沉思的時候,這9個數字很可能讓你頭痛不已,脈搏加快,惱火不已。不過,當你成功填完所有數字的時候,你肯定會感到欣喜若狂。有數獨迷宣稱,做此類游戲,一名大學教授很可能不敵一名工廠工人。 看起來很像中國古代的九宮格。。。。
E. 急需數獨一類的題!
數獨在線玩:http://www.yz9981.cn/sudoku/index99.php
數獨在線計算器:http://www.shu.net/
F. 怎樣玩數獨
數獨顧名思義——每個數字只能出現一次。數獨是一種源自18世紀末的瑞士,後在美國發展、並在日本得以發揚光大的數字謎題。數獨盤面是個九宮,每一宮又分為九個小格。在這八十一格中給出一定的已知數字和解題條件,利用邏輯和推理,在其他的空格上填入1-9的數字。使1-9每個數字在每一行、每一列和每一宮中都只出現一次。 這種游戲全面考驗做題者觀察能力和推理能力,雖然玩法簡單,但數字排列方式卻千變萬化,所以不少教育者認為數獨是訓練頭腦的絕佳方式。
基礎摒除法
基礎摒除法就是利用1 ~ 9 的數字在每一行、每一列、每一個九宮格都只能出現一次的規則進行解題的方法。基礎摒除法可以分為行摒除、列摒除、九宮格摒除。
實際尋找解的過程為:
尋找九宮格摒除解:找到了某數在某一個九宮格可填入的位置只餘一個的情形;意即找到了 該數在該九宮格中的填入位置。
尋找列摒除解:找到了某數在某列可填入的位置只餘一個的情形;意即找到了該數在該列中的填入位置。
尋找行摒除解:找到了某數在某行可填入的位置只餘一個的情形;意即找到了該數在該行中的填入位置。
唯一解法
當某行已填數字的宮格達到8個,那麼該行剩餘宮格能填的數字就只剩下那個還沒出現過的數字了。成為行唯一解.
當某列已填數字的宮格達到8個,那麼該列剩餘宮格能填的數字就只剩下那個還沒出現過的數字了。成為列唯一解.
當某九宮格已填數字的宮格達到8個,那麼該九宮格剩餘宮格能填的數字就只剩下那個還沒出現過的數字了。成為九宮格唯一解
具體方法有N多
可參考
G. 求數獨網站,越多越好!
http://www.sudoku.name/index-cn.php這個,我一直在玩!