3,881
社区成员
发帖
与我相关
我的任务
分享
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <time.h>
// solve sudoku puzzle
// using the digits 1 through 9 fill every space ont the board with
// the missing numbers. Every row, column and 3x3 box must contain
// all of the digits 1 through 9.
//
class sudoku{
public:
sudoku(){ memset(this, 0, sizeof(sudoku)); }
sudoku(const sudoku& rhs){ memcpy(this, &rhs,sizeof(sudoku)); }
void print(bool nice=false)const;
void preset_cell_value(int i, int value){
if(get_is_cell_preset(i))
throw "this place already has presets";
if(!check_set_cell_value(i,value))
throw "preset is creating confliction!";
set_is_cell_preset(i);
}
void preset_cell_value(int r, int c, int value){
preset_cell_value(r*n+c, value);
}
void solve(){ back_track(0); }
int count_solutions(){ count=0; back_track_2(0); return count;}
void unset_cell_value(int r, int c){
unset_cell_value(r*n+c);
}
static void generate();
void clear(){ memset(this, 0, sizeof(sudoku));}
private:
//sudoku(const sudoku&);
sudoku& operator=(const sudoku&);
void back_track(int i);
void back_track_2(int i); //count
void back_track_3(int i, int* cnt); //exit on dup
// return 0 if puzzle has 0 solution
// 1 1
// 2 if more than 1 solutons
int check_puzzle()const{
sudoku s(*this);
int count=0;
s.back_track_3(0,&count);
return count;
}
int get_cell_value(int i)const{ return cells[i]; }
int get_cell_value(int r, int c)const{ return cells[r*n+c]; }
void set_cell_value(int i, int value);
void set_cell_value(int r, int c, int value){
set_cell_value(r*n+c, value);
}
bool check_set_cell_value(int i, int value);
bool check_set_cell_value(int r, int c, int value){
return check_set_cell_value(r*n+c, value);
}
void unset_cell_value(int i);
//void unset_cell_value(int r, int c){
// unset_cell_value(r*n+c);
//}
bool get_is_cell_preset(int i)const;
bool get_is_cell_preset(int i, int j)const{
return get_is_cell_preset(i*n+j);
}
void set_is_cell_preset(int i);
void unset_is_cell_preset(int i);
bool get_row_has_value(int row, int value)const;
bool get_col_has_value(int col, int value)const;
bool get_sqr_has_value(int i, int value)const;
void set_row_has_value(int row, int value);
void set_col_has_value(int col, int value);
void set_sqr_has_value(int col, int value);
void unset_row_has_value(int row, int value);
void unset_col_has_value(int col, int value);
void unset_sqr_has_value(int col, int value);
private:
const static int n=9;
const static int nn=n*n;
const static int sqrtn=3;
int count; // count # of solutions to a specified prefix;
int cells[nn];
//char bits[(4*nn+7)/8];
bool presets[nn];
bool row_map[n][n];
bool col_map[n][n];
bool sqr_map[n][n];
// four bitsets showing
// 1. if a cell's value is preset
// 2. if a value exists in a row
// 3. if a value exists in a column
// 4. if a value exists in a square
};
bool sudoku::get_is_cell_preset(int i)const
{
return presets[i];//bits[i>>3] & (1<<(i&7));
}
void sudoku::set_is_cell_preset(int i)
{
presets[i]=true;//bits[i>>3] |= (1<<(i&7));
}
void sudoku::unset_is_cell_preset(int i)
{
presets[i]=false;//bits[i>>3] &= ~(1<<(i&7));
}
bool sudoku::get_row_has_value(int row, int value)const
{
//int s=nn+row*9+value-1;
return row_map[row][--value];//get_is_cell_preset(s);
}
bool sudoku::get_col_has_value(int col, int value)const
{
//int s=nn*2+col*9+value-1;
return col_map[col][--value];//get_is_cell_preset(s);
}
bool sudoku::get_sqr_has_value(int i, int value)const
{
//int s=nn*3+i*9+value-1;
return sqr_map[i][--value];//get_is_cell_preset(s);
}
void sudoku::set_row_has_value(int row, int value)
{
//int s=nn+row*9+value-1;
//set_is_cell_preset(s);
row_map[row][--value]=true;
}
void sudoku::set_col_has_value(int col, int value)
{
//int s=nn*2+col*9+value-1;
//set_is_cell_preset(s);
col_map[col][--value]=true;
}
void sudoku::set_sqr_has_value(int i, int value)
{
//int s=nn*3+col*9+value-1;
//set_is_cell_preset(s);
sqr_map[i][--value]=true;
}
void sudoku::unset_row_has_value(int row, int value)
{
//int s=nn+row*9+value-1;
//unset_is_cell_preset(s);
row_map[row][--value]=false;
}
void sudoku::unset_col_has_value(int col, int value)
{
//int s=nn*2+col*9+value-1;
//unset_is_cell_preset(s);
col_map[col][--value]=false;
}
void sudoku::unset_sqr_has_value(int i, int value)
{
//int s=nn*3+i*9+value-1;
//unset_is_cell_preset(s);
sqr_map[i][--value]=false;
}
// value should be 1-9, i should be 0 to nn-1
// if want to set a cell to 0 (clear), use
// unset_cell_value
//
void sudoku::set_cell_value(int i, int value)
{
set_row_has_value(i/n, value);
set_col_has_value(i%n, value);
set_sqr_has_value(i/n/3*3+i%n/3, value);
cells[i]=value;
}
// return false if putting value in cell i results in
// conflict. otherwise make the change and return true
//
bool sudoku::check_set_cell_value(int i, int value)
{
if( get_row_has_value(i/n, value) |
get_col_has_value(i%n, value) |
get_sqr_has_value(i/n/3*3+i%n/3, value) )
return false;
set_cell_value(i,value);
return true;
}
void sudoku::unset_cell_value(int i)
{
int value=cells[i];
if(value==0)return;
unset_row_has_value(i/n, value);
unset_col_has_value(i%n, value);
unset_sqr_has_value(i/n/3*3+i%n/3, value);
unset_is_cell_preset(i);
cells[i]=0;
}
void sudoku::print(bool nice)const
{
if(nice){
for(int i=0; i<n; ++i)
{
for(int j=0; j<n; ++j){
std::cout<<(get_cell_value(i,j)==0?' ':
(char)('0'+get_cell_value(i,j)))
<<" ";
if(j==2 || j==5)
std::cout<<"| ";
}
std::cout<<std::endl;
if(i==2 || i==5)
std::cout<<"=========+==========+=========\n";
else
std::cout<<"---------+----------+---------\n";
}
}else{
for(int i=0; i<n; ++i)
for(int j=0; j<n; ++j)
std::cout<<get_cell_value(i,j)<<(j==n-1?'\n':' ');
}
}
void sudoku::generate()
{
srand(time(NULL));
sudoku s;
int i,j,k,n;
while(true){
for(n=0; n<26; ++n){
do{
i=rand()%9;
j=rand()%9;
}while(s.get_is_cell_preset(i,j));
while(true){
try{
s.preset_cell_value(i,j,rand()%9+1);
break;
}catch(...){}
}
}
if(s.check_puzzle()==0){ //dead end
s.clear();
}else
break;
}
//s.print();
while(true){
do{
i=rand()%9;
j=rand()%9;
}while(s.get_is_cell_preset(i,j));
again:
while(true){
try{
k=rand()%9+1;
//std::cout<<"1:preset ("<<i<<','<<j<<") to "<<k<<std::endl;
s.preset_cell_value(i,j,k);
break;
}catch(...){}
}
n=s.check_puzzle();
//std::cout<<n<<std::endl;
//s.print();
//std::cout<<std::endl;
if(n==1)
break;
else if(n==0){
s.unset_cell_value(i,j);
goto again;
}
}
//std::cout<<"\nbefor trimming\n";
// remove redundancy
for(i=0; i<81; ++i){
if(s.get_is_cell_preset(i)){
int v=s.get_cell_value(i);
s.unset_cell_value(i);
if(s.check_puzzle()!=1)
s.preset_cell_value(i,v);
}
}
for(i=0,n=0; i<81; ++i)
if(s.get_is_cell_preset(i))
++n;
std::cout<<n<<" cells are preset:"<<std::endl;
s.print(true);
}
void sudoku::back_track(int i)
{
if(i==nn){ // find a solution
std::cout<<"Find a solution:"<<std::endl;
print();
std::cout<<std::endl;
return;
}
if(get_is_cell_preset(i))
back_track(i+1);
else
for(int j=1; j<n+1; ++j){
if(check_set_cell_value(i,j))
back_track(i+1);
unset_cell_value(i);
}
}
void sudoku::back_track_2(int i)
{
if(i==nn){ // find a solution
++count;
if(count%1000000==0)
std::cout<<count<<std::endl;
return;
}
if(get_is_cell_preset(i))
back_track_2(i+1);
else
for(int j=1; j<n+1; ++j){
if(check_set_cell_value(i,j))
back_track_2(i+1);
unset_cell_value(i);
}
}
void sudoku::back_track_3(int i, int* count)
{
if(i==nn){ // find a solution
++*count;
return;
}
if(get_is_cell_preset(i))
back_track_3(i+1,count);
else
for(int j=1;*count<2 && j<n+1; ++j){
if( check_set_cell_value(i,j))
back_track_3(i+1,count);
unset_cell_value(i);
}
}
int main()
{
sudoku s;
sudoku::generate();
return 0;
}
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
class sukodu{
public:
typedef void (*fount_solution_action)(sukodu*);
typedef void (*continue_search)(const sukodu*);
public:
sukodu(){ memset(this, 0, sizeof(*this)); }
// sukodu(const sukodu& rhs){ memcpy(this, &rhs, sizeof(*this)); }
bool set(unsigned cell_no, unsigned value){ return set(cell_no/9, cell_no%9, value); }
bool set(unsigned row, unsigned col, unsigned value);
void unset(unsigned row, unsigned col);
void unset(unsigned cell_no){ unset(cell_no/9, cell_no%9 ); }
void solve();
unsigned cell(unsigned row, unsigned col)const{ return cells[row][col]; }
unsigned cell(unsigned cell_no)const{ return cell(cell_no/9, cell_no%9); }
private:
void back_track(unsigned i);
unsigned count_choice(unsigned cell_no){ return count_choice(cell_no/9, cell_no%9); }
unsigned count_choice(unsigned row, unsigned col);
unsigned square_no(unsigned row, unsigned col){
return row/3*3+col/3;
}
private:
unsigned cells[9][9];
unsigned rowflags[9];
unsigned colflags[9];
unsigned sqrflags[9];
unsigned perm[81];
unsigned count;
public:
//static found_solution_action fsa;
//;
};
template <typename T>
T& operator<<(T& os, const sukodu& s);
template <typename T>
T& operator>>(T& is, sukodu& s);
// 从标准输入读数独题
// 题目的格式是81个0-9的整数,0表示题中该位置尚未确定。
//
int main()
{
sukodu s;
std::cin>>s;
s.solve();
std::cout<<s<<std::endl;
}
/* set cell at (row, col) to value if it's feasible and return true
* otherwise returns false;
*/
bool
sukodu::set(unsigned row, unsigned col, unsigned value)
{
short mask= 1<< value-1;
if( rowflags[row] & mask ||
colflags[col] & mask ||
sqrflags[square_no(row,col)] & mask
)
return false;
cells[row][col]=value;
rowflags[row] |= mask;
colflags[col] |= mask;
sqrflags[square_no(row,col)] |= mask;
return true;
}
/* reset value at cells[row][col] to 0(not yet set)
* of course, all relevant masks need to be adjusted
*/
void
sukodu::unset(unsigned row, unsigned col)
{
unsigned mask = ~(1<< cells[row][col]-1);
cells[row][col] = 0;
rowflags[row] &= mask;
colflags[col] &= mask;
sqrflags[square_no(row,col)] &= mask;
}
template <typename T>
T& operator<<(T& os, const sukodu& s)
{
for(unsigned i=0; i<9; ++i){
for(unsigned j=0; j<9; ++j){
os<<s.cell(i,j)<<(j==8?'\n':' ');
if(j==2 || j==5)
os<<'|';
}
if(i==2 or i==5)
os<<"------+------+------\n";
}
}
template <typename T>
T& operator>>(T& is, sukodu& s)
{
unsigned u;
for(unsigned i=0; i<9; ++i){
for(unsigned j=0; j<9; ++j){
is>>u;
if( u>9 )
throw "Invalid input - greater than 9";
s.set(i,j,u);
}
}
}
void
sukodu::solve()
{
for(unsigned i=0; i<81; ++i)
perm[i]=i; // intialize to natural permutation;
count=0;
back_track( 0 );
}
void
sukodu::back_track(unsigned i)
{
if(i==81){ // got a solution
++count; // count is used as solution count;
std::cout<<*this;
return;
}
unsigned min_choice=10, min_index, cur_choice;
for(unsigned j=i; j<81; ++j){
cur_choice = count_choice(perm[j]);
if( cur_choice == 0 ) // dead branch
return; // exit function
if( cur_choice ==1 ){ // preset values;
min_index=j;
break;
}
if ( cur_choice < min_choice ){
min_choice = cur_choice;
min_index = j;
}
}
std::swap(perm[i], perm[min_index]);
// now permutation[i] has the cell_no who has the least children
//
if( cell(perm[i])!=0 ){
back_track( i+1 );
return;
}
for(unsigned j=1;count<2 && j<10; ++j){
if( set(perm[i],j) ){
//printf("i=%d, perm[i]=%d, j=%d\n",i,perm[i],j);
//std::cout<<*this<<std::endl;
back_track( i+1); // more than one branches.
unset( perm[i]);
}
}
}
static unsigned bit_count(short s)
{
int count=0;
while(s){
++count;
s &= s-1;
}
return count;
}
unsigned sukodu::count_choice(unsigned row, unsigned col)
{
/* if the cell contains nozero value, it's already been determined
* at least on the search path.
*/
return cell(row,col)!=0 ? 1 :
bit_count(0x1ff & ~rowflags[row] & ~colflags[col] &
~sqrflags[ square_no(row,col) ]);
}