您的位置:首页 > 编程语言 > C语言/C++

C++算法之解数独

2018-03-29 20:41 330 查看
输入数独矩阵,未知数字用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函数,至于更新多少次,无法保证。先定义一个矩阵的备份,如果在某一次更新之后,新的矩阵和备份矩阵完全相同,则说明矩阵内已经没有数据可以更新了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C 数独