C++算法之解数独
2018-03-29 20:41
330 查看
输入数独矩阵,未知数字用0代替,数字之间用空格隔开。
该程序只能解初级和中级的数独,高级数独暂时还没有能力。
效果截图:
源代码:
定义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函数,至于更新多少次,无法保证。先定义一个矩阵的备份,如果在某一次更新之后,新的矩阵和备份矩阵完全相同,则说明矩阵内已经没有数据可以更新了。
该程序只能解初级和中级的数独,高级数独暂时还没有能力。
效果截图:
源代码:
#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++实现
- 解数独算法--C++实现
- C++每日一练(STL算法——remove)
- ccf c++ 分蛋糕算法
- 蓝桥杯-算法提高 8皇后·c++实现
- 算法:combination in c++
- C++ STL 算法简介
- 传统高斯模糊与优化算法(附完整C++代码)
- C/C++面试之算法系列--整数数组的循环右移
- 【算法学习】B-Tree编程实现(C++模板类封装)
- C++递归实现欧几里德(Euclid)算法
- SIFT特征2-基于OpenCV和C++的算法实现
- C/C++中几种经典的垃圾回收算法
- 20170219C++项目班02_02递归下降算法/解析器/Scanner实现
- C++之算法题模板
- C/C++计算一重定积分和二重定积分(纯暴力算法实现)
- 数据结构、算法与应用 (C++描述) 第二版 1.19
- KMP-看毛片算法 c++
- 阶乘相关的算法及其C++实现
- 算法 - 求和为n的连续正整数序列(C++)