解数独程序源代码,可检测题目是否合法,可解无解/一个解/多个解的情况。leetcode测试较快,现在分享,望指教!

<pre name="code" class="cpp">//sudoku.cpp// 解数独函数
#include "sudoku.h"
#include <stdlib.h>
#include <iostream>

using namespace std;

void sudoku(char array[9][9])
{
	int sudo[9][9]={0};
	int number_of_empty=0;                                                   //定义需要填入数的个数
	Conversion_char_int(array,sudo);	                                    //转换成数字型 数独题目
	if (!Inspection(sudo))	                                               //检查题目是否合法。
	{
		cout<<"该数独题目不符合要求,请检查后重新输入。"<<endl;
		system("pause");
		exit(1);
	}
	number_of_empty=Blank_number(sudo);                     //计算需要填入数的个数

	Node * node_sudu=(Node *)malloc(sizeof(Node)*number_of_empty);               //给每一个空格申请一个Node 结构体。
	if(node_sudu==NULL)
	{
		cout<<"Node结构体内存分配失败!"<<endl;
		system("pause");
		exit(1);
	}

	Initialization_col_row(sudo,node_sudu);	                             //确定Node结构体重每一个元素的  col 和row 的值。

	Solving(sudo,number_of_empty,node_sudu);

}


void Conversion_char_int(char a[9][9],int p[9][9])	                //转换函数,讲字符型数组  转化成整形数组,'.'变为0。
{
	for (int i=0;i<9;i++)
		for (int j=0;j<9;j++)
		{
			if (a[i][j]=='.')
			{
				p[i][j]=0;
			}
			else if(57>=int(a[i][j])&&int(a[i][j])>=49)
			{
				p[i][j]=(a[i][j]-'0');
			}
			else
			{
			  cout<<"该数独题目不符合要求,请检查后重新输入。"<<endl;
			  system("pause");
			}
		}
}

bool  Inspection(int sudo[9][9])
{
	int temp[10]={0,0,0,0,0,0,0,0,0,0};
	int i,j,m,n;
	for(i=0;i<9;i++)
		for(j=0;j<9;j++)
			if(sudo[i][j]!=0)
			{
				//检查所在行的元素是否重复
				for(m=0;m<10;m++)
					temp[m]=0;
				for(m=0;m<9;m++)
					if(sudo[i][m]!=0)
					{
						if(temp[sudo[i][m]]==0)
							temp[sudo[i][m]]=1;
						else
							return false;
					}
					//检查所在列数字是否合法
					for(m=0;m<10;m++)
						temp[m]=0;
					for(m=0;m<9;m++)
						if(sudo[m][j]!=0)
						{
							if(temp[sudo[m][j]]==0)
								temp[sudo[m][j]]=1;
							else
								return false;
						}
						//检查所在小九宫格中数字是否合法(i,j)与小九宫格到位置(i/3*3,j/3*3) 转换。
						for(m=0;m<10;m++)
							temp[m]=0;
						for(m=0;m<3;m++)
							for(n=0;n<3;n++)
								if(sudo[i/3*3+m][j/3*3+n]!=0)
								{
									if(temp[sudo[i/3*3+m][j/3*3+n]]==0)
										temp[sudo[i/3*3+m][j/3*3+n]]=1;
									else
										return false;
								}
			}
			return true;
}


int Blank_number(int sudo[9][9])	                                 //计算所给数独中待填入的空白数
{
	int i,j,num=0;
	for(i=0;i<9;i++)
		for(j=0;j<9;j++)
			if(sudo[i][j]==0)
				num++;
	return num;
}





void Initialization_col_row(int sudo[9][9],Node * node_sudo)
{
	int m=0;
	for (int i=0;i<9;i++)
		for(int j=0;j<9;j++)
		{ if (sudo[i][j]==0)
		   {
			 (node_sudo+m)->col=i;
			 (node_sudo+m)->row=j;
			  m++;
		   }
		}
}

int Find_value(int sudo[9][9],Node * node_sudo)                                //找到合法的解。   value[10],第一个值存总共可以由多少个元素。 可以取得值value=0,否则=1。
{																										 
	int m,n,i=node_sudo->col,j=node_sudo->row;

	for(m=0;m<10;m++)
		node_sudo->value[m]=0;
	for(m=1;m<10;m++)
	{
		node_sudo->value[sudo[i][m-1]]=1;                  //筛选行方向的值
		node_sudo->value[sudo[m-1][j]]=1;                  //筛选列方向的值
	}
	for(m=0;m<3;m++)	                                   //筛选小九宫格方向的值
		for(n=0;n<3;n++)
			node_sudo->value[sudo[i/3*3+m][j/3*3+n]]=1;

    node_sudo->value[0]=0;	                                        //node->value[0]记录候选值个数,前面的循环可能会修改掉它,需要重新赋0值
	for(m=1;m<10;m++)
		if(node_sudo->value[m]==0)  node_sudo->value[0]++;

	
	for(m=1;m<10;m++)	                                           //找到第一个可以取的值
		if(node_sudo->value[m]==0)
		{
			node_sudo->value[m]=1;
			node_sudo->value[0]--;
			break;
		}

		//返回候选值m,若无候选值可用,返回错误标记-1
		if(m==10)
			return -1;
		else
			return m;
}




void  Solving(int sudo[9][9],int num_of_empty,Node* node_sudo)               //num_of_empty  为总共空格数。
{
	int k=0;       //记录已经求得了几个解。
	int number=1;  //从第一个空格数开始求解。
	while(0<number && number<=(num_of_empty+1))
	{
		int i=(node_sudo+(number-1))->col;
		int j=(node_sudo+(number-1))->row;

		if (number>num_of_empty)
		{   
			k++; int count=0;
			for (int i=0;i<num_of_empty;i++)
			{
				if ((node_sudo+i)->value[0]==0)   { count++;}
			}
			//第一种情况 最后一次试探 刚好是得到所有解。提前结束
			if (count==num_of_empty)
			{
				cout<<"这是第"<<k<<"个答案:"<<endl;
				Print_sudo(sudo);
				cout<<"已经得到所有答案"<<endl;
				number++  ;
			}
			else if (count!=num_of_empty)	                 //向前回溯求解。。。
			{
				cout<<"这是第"<<k<<"个答案:"<<endl;
				Print_sudo(sudo);
				--number;
			}
		}
		else if ( 0<number  &&  number<=num_of_empty )
		{  

			if (sudo[i][j]!=0)
			{   
				if ((node_sudo+(number-1))->value[0]==0)
				{
					sudo[i][j]=0;
					(--number);
				}
				else if ((node_sudo+(number-1))->value[0]!=0 )
				{
					for (int index=1;index<10;index++)
					{    
						if ((node_sudo+(number-1))->value[index]==0)
						{   
							sudo[i][j]=index;
							(node_sudo+(number-1))->value[index]=1;
							(node_sudo+(number-1))->value[0]--; 
							break;
				  }
			  }
					(++number);

				}



			}
			else if(sudo[i][j]==0)
			{  
				sudo[i][j]=Find_value(sudo,(node_sudo+number-1));
				if (sudo[i][j]==-1)
				{   
					sudo[i][j]=0;
					(--number);
				}
				else if (sudo[i][j]!=-1)
				{   
					(++number);
				}
			}
		}
	}

	if (number<=0)
	{   
		if(k==0) { cout<<"该数独没有解"<<endl; }

		if(k!=0) { cout<<"已得到该数独的所有解"<<endl; } 

	}
}

void Print_sudo(int sudo[9][9])
{
	for (int i=0;i<9;i++)
		for (int j=0;j<9;j++)
		{
			cout<<sudo[i][j]<<"  ";
			if (j%8==0&&j!=0)
			{
				cout<<endl;
			}
		}
}

///main.cpp///主函数//里面有测试题目//
//题目要求,数值为字符型,需要填的位置用字符‘.’代替。///

#include <iostream>
#include "sudoku.h"

using namespace std;


int main()
{
	char arr[9][9]={'5', '3', '.', '.', '7', '.', '.', '.', '.',
		            '6', '.', '.', '1', '9', '5', '.', '.', '.',
	              	'.', '9', '8', '.', '.', '.', '.', '6', '.',
		            '8', '.', '.', '.', '6', '.', '.', '.', '3',
	                '4', '.', '.', '8', '.', '3', '.', '.', '1',
		            '7', '.', '.', '.', '2', '.', '.', '.', '6',
		            '.', '6', '.', '.', '.', '.', '2', '8', '.',
		            '.', '.', '.', '4', '1', '9', '.', '.', '5',
		            '.', '.', '.', '.', '8', '.', '.', '7', '9'};

	char arr_1[9][9]={'.','9','.','1','.','.','5','.','.',
		              '.','.','.','.','7','9','8','.','1',
	              	  '2','.','.','.','.','.','.','.','6',
		              '.','3','.','.','.','.','.','.','.',
		              '.','.','.','7','8','1','.','.','.',
		              '.','.','4','.','.','.','.','2','.',
		              '7','.','.','6','.','.','.','.','4',
		              '6','.','1','5','3','.','.','.','.',
					  '.','.','9','.','.','7','.','6','.'};

	char arr_2[9][9]={'.','.','2','.','6','.','.','.','.',
		'.','.',	'6',	'.',	'.',	'7',	'.',	'.',	'9',
		'.',	'.',	'7',	'.',	'.',	'8',	'4',	'.',	'.',
		'9',	'.',	'.',	'.',	'3',	'.',	'.',	'.',	'1',
		'3',	'.',	'.',	'5',	'.',	'2',	'.',	'.',	'4',
		'6',	'.',	'.',	'.',	'1',	'.',	'.',	'.',	'3',
		'.',	'.',	'5',	'3',	'.',	'.',	'8',	'.',	'.',
		'8',	'.',	'.',	'6',	'.',	'.',	'5',	'.',	'.',
		'.',	'.',	'.',	'.',	'2',	'.',	'9',	'.',	'.'};



    cout<<"数独题目为:"<<endl;
	for (int i=0;i<9;i++)
	   for (int j=0;j<9;j++)
	   {
		   cout<<arr_2[i][j]<<"  ";
		   if (j%8==0&&j!=0)
		   {
			   cout<<endl;
		   }
	   }

   	 sudoku( arr_2);

	return 0;
}




//sudoku.h/头文件void sudoku(char array[9][9]); //解数独游戏函数。void Conversion_char_int(char a[9][9],int p[9][9]); //转换函数,讲字符型数组 转化成整形数组,'.'变为0。bool Inspection(int sudo[9][9]); //检查该题目是否合法。int Blank_number(int sudo[9][9]); //计算所给数独中待填入的空白数typedef struct node //代表每个待填空格属性,包括对应的位置,以及可以取得值。{ int col; int row; int value[10];}Node; //带有typedef 字样的结构体,在申请结构体变量的时候, Node 可以代替 struct node。void Initialization_col_row(int sudo[9][9],Node * node_sudo); //确定Node结构体重每一个元素的 col 和row 的值。int Find_value(int sudo[9][9],Node * node_sudo); //找该空格可能的解,并试着求第一个解。void Solving(int sudo[9][9],int num_of_empty,Node* node_sudo); //解数独问题void Print_sudo(int sudo[9][9]); //输出求得的数独的解。


 
</pre><pre name="code" class="cpp">
哈哈,如果对大家有用,希望交流,得到大家的关注。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值