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这个,我一直在玩!