请教一下那些数独(一般的那种九宫格)程序是怎么写出来的?

兔子的传说 2014-01-30 09:04:07
如题所示,如题所示。
...全文
638 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
孩皮妞野 2014-02-01
  • 打赏
  • 举报
回复
这个是生成数独题目的,不过还是不是最终的版本。它生成的是文本格式的。丢的那个可以指定随机种子,可以指定生成的题数,然后生成方便打印出来做的速度题。这个生成的题目都是超难的--完全没有冗余的,即去掉任何一个数字,新题都会有不止一种解。我没有耐心解出任何一道,因为不得不用一些类似回溯的办法,这个对人类来说就太boring了。

#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;
}
孩皮妞野 2014-02-01
  • 打赏
  • 举报
回复
最终的能生成数独题目的(html格式)的程序找不到了,这个是解数独的,效率应该是相当好的。 使用的是利用了启发信息的回溯法,代码显得略复杂。没有编译,应该可以吧。

#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) ]);
}

孩皮妞野 2014-02-01
  • 打赏
  • 举报
回复
回溯法秒杀。我写过一个生成数独题的,中间要解n次数独题。回头看找不找得到。
threenewbee 2014-01-30
  • 打赏
  • 举报
回复
http://bbs.csdn.net/topics/390039859

3,881

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧