C++算法之解数独

输入数独矩阵,未知数字用0代替,数字之间用空格隔开。
该程序只能解初级和中级的数独,高级数独暂时还没有能力。
效果截图:

源代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> a{0,1,2,3,4,5,6,7,8,9};
vector<vector<int>>b(10,a);
vector<vector<vector<int>>> arr(10,b);
int get(int row,int column){
	return arr[row][column][0];
}
void set(int row,int column,int value){
	for(int i=1;i<10;i++){
		arr[row][i][value]=0;
		arr[i][column][value]=0;
	}
	for(int i=(row-1)/3*3+1;i<=((row-1)/3+1)*3;i++)
		for(int j=(column-1)/3*3+1;j<=((column-1)/3+1)*3;j++)
			arr[i][j][value]=0;
	for(auto&x:arr[row][column])
		x=0;
	arr[row][column][0]=value;
}

int get_value_times_in_row(int row,int value){
	int times=0;
	for(int i=1;i<10;i++){
		if(arr[row][i][value]!=0)
			times++;
	}
	return times;
}
int get_value_times_in_column(int column,int value){
	int times=0;
	for(int i=1;i<10;i++){
		if(arr[i][column][value]!=0)
			times++;
	}
	return times;
}
int get_value_times_in_grid(int row,int column,int value){
	int times=0;
	for(int a=(row-1)/3*3+1;a<=((row-1)/3+1)*3;a++){
		for(int b=(column-1)/3*3+1;b<=((column-1)/3+1)*3;b++){
			if(arr[a][b][value]!=0)
				times++;
		}
	}
	return times;
}

void brush(){
	
	//此位置只剩下一种可能 
	for(int i=1;i<10;i++){
		for(int j=1;j<10;j++){
			if(get(i,j)==0){
				int num=0;
				int index=0;
				for(int k=1;k<10;k++)
					if(arr[i][j][k]!=0){
						num++;
						index=k;
					}
				if(num==1)
					set(i,j,arr[i][j][index]);
			}
		}
	}
	
	//此数字只能填在此位置 
	for(int i=1;i<10;i++)
		for(int j=1;j<10;j++)
			if(get(i,j)==0)
				for(int k=1;k<10;k++)
					if(arr[i][j][k]!=0
					&&(get_value_times_in_row(i,k)==1
					||get_value_times_in_column(j,k)==1
					||get_value_times_in_grid(i,j,k)==1))
						set(i,j,k);
}
//输出矩阵 
void out(){
	for(int i=1;i<10;i++){
		for(int j=1;j<10;j++)
			cout<<get(i,j)<<' ';
		cout<<endl;
	}
}
//输出候选数字 
void candidate(){
	for(int i=1;i<10;i++){
		for(int j=1;j<10;j++){
			if(get(i,j)!=0)
				cout<<get(i,j)<<'\t';
			else{
				for(int k=1;k<10;k++)
					if(arr[i][j][k]!=0)
						cout<<arr[i][j][k];
				cout<<'\t';
			}
		}
		cout<<endl;
	}
}

bool is_exist_zero(){
	for(int i=1;i<10;i++)
		for(int j=1;j<10;j++)
			if(get(i,j)==0)
				return true;
	return true;
}
struct location{
	int x;
	int y;
	vector<int> values;
}loc;
vector<location> find_only_two_candidate(){
	vector<location> res;
	for(int i=1;i<10;i++)
		for(int j=1;j<10;j++)
			if(get(i,j)==0){
				int num=0;
				for(int k=1;k<10;k++)
					if(arr[i][j][k]!=0)
						num++;
				if(num==2){
					loc.x=i;
					loc.y=j;
					for(int k=1;k<10;k++)
						if(arr[i][j][k]!=0)
							loc.values.push_back(k);
					res.push_back(loc);
				}
			}
	return res;
}
int main(){
	int token;
	for(int i=1;i<=9;i++){
		for(int j=1;j<=9;j++){
			cin>>token;
			if(token!=0)
				set(i,j,token);
		}
	}
	vector<vector<vector<int>>> tmp;
	while(tmp!=arr){
		tmp=arr;
		brush();
	}
	cout<<endl;
	out();
//	cout<<endl;
//	candidate();
//	vector<location> locations=find_only_two_candidate();
//	bool is_ok=false;
//	for(location loctest:locations){
//		for(int i=0;i<2;i++){
//			arr=tmp;
//			set(loctest.x,loctest.y,loctest.values[i]);
//			vector<vector<vector<int>>> s;
//			while(s!=arr){
//				s=arr;
//				brush();
//			}
//			if(!is_exist_zero()){
//				is_ok=true;
//				break;
//			}
//		}
//		if(is_ok)
//			break;
//	}
	out();
}
代码简析:
定义10*10的矩阵,每行每列零位置冗余。矩阵的每个位置都是一个长度为10的数组,分别存0~9的候选数字,该位置真正的值放在0位置。定义完毕后,矩阵中每个位置的实际值都是0,候选数字都是1~9。

设置某一个位置的值(set函数):传入需要设置值的位置(第row行第column列)和值(value),将第row行所有的元素上的候选数字value删去,将第column列所有元素上的候选数字value删去,将需要设置值的元素的所在小宫格内所有元素上的候选数字value删去,最后,将该位置上的数组中的所有候选数字删去,并将0位置设置为value。
获取某一位置上的值(get函数):获取第i行第j列位置上的值,就是返回该位置上数组0位置上的值。如果返回值是0,说明该位置值并没有确定。

更新矩阵(brush函数):第一种情况:随着值的设定,某些位置上的候选数字接连被删除,只剩下了一个候选数字,则这个候选数字就是该位置上的值;第二种情况:针对某一位置(i,j),在第i行或第j列或其所在宫格内的其他位置上都没有候选数字v,只有(i,j)位置上有候选数字v,则v就是该位置上的值。
一次更新并不能将全部的值更新完毕,需要多次,则循环调用brush函数,至于更新多少次,无法保证。先定义一个矩阵的备份,如果在某一次更新之后,新的矩阵和备份矩阵完全相同,则说明矩阵内已经没有数据可以更新了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值