如何解决在C ++中使用堆栈和回溯在数独求解器上工作,需要帮助修复我的算法
最初,我的算法涉及测试nxn数独的1-> n中的每个数字,但由于它无法解决16x16数独(算法运行了3个小时没有运气),我认为最好选择一个基于板上最有效和最少使用的编号的单元。我想我已经解决了大部分问题,例如我制作了一个二维矢量,称为用法(第一列是数字,第二列是用法),每次在板上进行更改时都会对其进行排序。现在,我可以解决一个简单的9x9和一个空的16x16,但是我在其他地方没有运气。想知道是否有人可以帮助我找出我缺乏逻辑的地方。
///我使用堆栈
#include <stack>
#include <vector>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
bool isRowValid(vector <vector <int>> &sudoku,int row,int possval);
bool isColumnValid(vector <vector <int>> &sudoku,int column,int possval);
int assignBlock9x9(int pos);
int assignBlock16x16(int pos);
int assignBlock25x25(int pos);
bool isBlockValid(vector <vector <int>> &sudoku,int possval);
bool isValidSingle(vector <vector <int>> &sudoku,int possval);
bool isRowValid2(vector <vector <int>> &sudoku,int possval);
bool isColumnValid2(vector <vector <int>>& sudoku,int possval);
bool isBlockValid2(vector <vector <int>>& sudoku,int possval);
bool isValidSingle2(vector <vector <int>>& sudoku,int possval);
int solve(vector <vector <int>>& sudoku);
vector <vector<int>> Usage(vector <vector <int>>& sudoku);
bool sortcol(const vector<int>& v1,const vector<int>& v2);
bool sortcol2(const vector<int>& v1,const vector<int>& v2);
void printSudoku(vector <vector <int>>& sudokusudoku);
void printUsage(vector<vector<int>>& usage);
/* easy sudoku (9x9_1.txt) - actually solves
0 4 0 0 0 0 1 7 9
0 0 2 0 0 8 0 5 4
0 0 6 0 0 5 0 0 8
0 8 0 0 7 0 9 1 0
0 5 0 0 9 0 0 3 0
0 1 9 0 6 0 0 4 0
3 0 0 4 0 0 7 0 0
5 7 0 1 0 0 2 0 0
9 2 8 0 0 0 0 6 0*/
/*solution
8 4 5 6 3 2 1 7 9
7 3 2 9 1 8 6 5 4
1 9 6 7 4 5 3 2 8
6 8 3 5 7 4 9 1 2
4 5 7 2 9 1 8 3 6
2 1 9 8 6 3 5 4 7
3 6 1 4 2 9 7 8 5
5 7 4 1 8 6 2 9 3
9 2 8 3 5 7 4 6 1*/
/*medium sudoku (9x9_2.txt) - can't solve
0 9 0 3 8 4 0 0 0
0 0 2 0 7 0 0 0 0
0 0 0 0 0 0 0 7 1
5 0 0 0 0 3 2 4 0
0 3 0 0 0 0 0 0 0
0 0 1 0 0 5 0 9 0
0 0 0 8 0 0 0 0 0
7 0 6 5 2 0 0 0 0
0 0 0 0 0 6 4 0 0*/
/*solution
1 9 7 3 8 4 5 6 2
8 5 2 6 7 1 9 3 4
4 6 3 9 5 2 8 7 1
5 8 9 7 1 3 2 4 6
6 3 4 2 9 8 7 1 5
2 7 1 4 6 5 3 9 8
3 1 5 8 4 7 6 2 9
7 4 6 5 2 9 1 8 3
9 2 8 1 3 6 4 5 7*/
/* hard sudoku (9x9_3.txt) - can't solve
7 9 0 0 0 0 0 0 3
0 0 0 0 0 0 0 6 0
8 0 1 0 0 4 0 0 2
0 0 5 0 0 0 0 0 0
3 0 0 1 0 0 0 0 0
0 4 0 0 0 6 2 0 9
2 0 0 0 3 0 0 0 6
0 3 0 6 0 5 4 2 1
0 0 0 0 0 0 0 0 0*/
/*solution
7 9 2 5 6 8 1 4 3
4 5 3 2 1 9 8 6 7
8 6 1 3 7 4 9 5 2
6 2 5 8 9 3 7 1 4
3 7 9 1 4 2 6 8 5
1 4 8 7 5 6 2 3 9
2 8 4 9 3 1 5 7 6
9 3 7 6 8 5 4 2 1
5 1 6 4 2 7 3 9 8*/
/* no solution sudoku (9x9_4.txt) - can't solve
0 0 0 0 0 0 0 0 7
7 2 0 3 0 9 0 0 1
0 0 8 7 0 5 0 6 0
5 0 2 8 9 0 0 0 0
0 4 0 5 0 1 0 9 0
0 0 0 0 6 3 7 0 5
0 3 0 9 0 6 1 7 0
2 0 0 1 0 7 0 5 3
9 0 0 0 0 0 0 0 0
*/
int main()
{
fstream MySudoku("9x9_1.txt");
vector <vector <int>> sudoku;
//input from text file
if (MySudoku.is_open()) {
string row;
while (getline(MySudoku,row)) {
stringstream rowelement (row);
string num;
vector <int> row;
while (getline(rowelement,num,' ')) {
if ((int)num[0] >= 65) {
row.push_back((int)num[0] - 55);
}
else {
row.push_back((int)num[0] - 48);
}
}
sudoku.push_back(row);
rowelement.clear();
//cout << row;
//cout << endl;
}
MySudoku.close();
}
//input from testing bot
/*string row;
int i = 0;
int rowsize = 9;
while (i < rowsize) {
getline(cin,row);
stringstream rowelement(row);
string num;
vector <int> row;
rowsize = 0;
while (getline(rowelement,' ')) {
if ((int)num[0] >= 65) {
row.push_back((int)num[0] - 55);
}
else {
row.push_back((int)num[0] - 48);
//cout << 500 + (int)num[0] - 48;
}
++rowsize;
}
//cout << rowsize;
sudoku.push_back(row);
rowelement.clear();
++i;
}
*/
//solving and printing out the resulting sudoku if possible
int solved = solve(sudoku);
if (solved == 1) {
printSudoku(sudoku);
}
else {
cout << "No Solution";
}
}
void printSudoku(vector <vector <int>>& sudoku) {
for (unsigned int i = 0; i < sudoku.size(); i++) {
for (unsigned int j = 0; j < sudoku.size(); j++) {
if (sudoku[i][j] >= 10) {
if (j == sudoku.size() - 1) {
cout << (char)(sudoku[i][j] + 55);
}
else {
cout << (char)(sudoku[i][j] + 55) << " ";
}
}
else {
if (j == sudoku.size() - 1) {
cout << sudoku[i][j];
}
else {
cout << sudoku[i][j] << " ";
}
}
}
cout << endl;
}
}
void printUsage(vector<vector<int>> &usage) {
for (vector <int> usagerow : usage) {
cout << usagerow[0] << " : " << usagerow[1] << " ";
}
cout << endl << endl;
}
int solve(vector <vector <int>>& sudoku) {
stack <pair<int,int>> solution;
vector <vector <int>> usage = Usage(sudoku);
//printUsage(usage);
///////////initializes solution
int breaker = 0;
//pushes value on empty cell
for (unsigned int row = 0; row < sudoku.size(); row++) {
if (breaker == 2002) {
break;
}
for (unsigned int column = 0; column < sudoku.size(); column++) {
if (breaker == 2002) {
break;
}
if (sudoku[row][column] == 0) {
//choose option based on usage and then change usage list
int vectorpos = 0;
while (!isValidSingle(sudoku,row,column,usage[vectorpos][0]) && vectorpos != sudoku.size() - 1) {
++vectorpos;
}
//cout << usage[vectorpos][0] << " was pushed at " << row << column << endl;
sudoku[row][column] = usage[vectorpos][0];
usage[vectorpos][1] = usage[vectorpos][1] + 1;
sort(usage.begin(),usage.begin() + usage.size(),sortcol);
sort(usage.begin(),sortcol2);
solution.push(make_pair(row,column));
breaker = 2002;
break;
}
}
}
//printSudoku(sudoku);
//just prints out the usage vector {not useful}
//printUsage(usage);
/////actual solution
bool solved = false;
while (!solved) {
//cout << "top of stack is " << solution.top().first << solution.top().second << endl;
int lastrow = solution.top().first;
int lastcolumn = solution.top().second;
//checks if sudoku is in invalid state
if (!isValidSingle2(sudoku,lastrow,lastcolumn,sudoku[lastrow][lastcolumn])) {
//copy of usage vector to allow us to see if we're at the last option for the cell
vector <vector <int>> usagefuture = usage;
for (vector<int> &usagerowdec : usagefuture) {
if (sudoku[solution.top().first][solution.top().second] == usagerowdec[0]) {
usagerowdec[1] = usagerowdec[1] - 1;
sort(usagefuture.begin(),usagefuture.begin() + usagefuture.size(),sortcol);
sort(usagefuture.begin(),sortcol2);
break;
}
}
//cout << "future -> "; printUsage(usagefuture);
//keeps popping last decision until sudoku no longer in invalid state
while (sudoku[solution.top().first][solution.top().second] == usagefuture[sudoku.size()-1][0]) {
//looks for where the last entered value occurs in the usage vector
int val = sudoku[solution.top().first][solution.top().second];
for (vector <int> usagerowdec : usage) {
if (usagerowdec[0]==val) {
//sets cell to 0 and pops
sudoku[solution.top().first][solution.top().second] = 0;
//cout << usagerowdec[0] << " was set back to 0" /*<< solution.top().first << solution.top().first*/ << endl;
solution.pop();
//cout << "top of stack is Now " << solution.top().first << solution.top().second << endl;
//permanently changes the usage vector
usage = usagefuture;
sort(usage.begin(),sortcol);
sort(usage.begin(),sortcol2);
break;
}
}
if (solution.size() == 0) {
return 0;
}
//copy of usage vector to allow us to see if we're at the last option for the cell
usagefuture = usage;
for (vector<int>& usagerowdec : usagefuture) {
if (sudoku[solution.top().first][solution.top().second] == usagerowdec[0]) {
usagerowdec[1] = usagerowdec[1] - 1;
sort(usagefuture.begin(),sortcol);
sort(usagefuture.begin(),sortcol2);
break;
}
}
//cout << "future -> "; printUsage(usagefuture);
}
if (solution.size() == 0) {
return 0;
}
else {
int row = solution.top().first;
int column = solution.top().second;
//printUsage(usage);
//decrements usage vector at value we're changing
for (vector<int>& usagerowdec : usage) {
if (sudoku[row][column] == usagerowdec[0]) {
usagerowdec[1] = usagerowdec[1] - 1;
sort(usage.begin(),sortcol2);
break;
}
}
//printSudoku(sudoku);
//finds which value we're on in the usage vector
int vectorpos = 0;
for (int i = 0; i < usage.size(); i++) {
if (sudoku[row][column] == usage[i][0]) {
vectorpos = i;
break;
}
}
//sees what next value we can set it to. If nothing it becomes the last possible value
while (!isValidSingle(sudoku,usage[vectorpos][0]) && vectorpos != sudoku.size() - 1) {
vectorpos++;
}
//cout << "vectorpos is " << vectorpos << ": ";
//completes the change
//cout << sudoku[row][column] << " was changed to " << usage[vectorpos][0] << " at " << row << column << endl;
sudoku[row][column] = usage[vectorpos][0];
usage[vectorpos][1] = usage[vectorpos][1] + 1;
sort(usage.begin(),sortcol);
sort(usage.begin(),sortcol2);
}
}
//if sudoku in valid state
else {
int breaker = 0;
//looks for empty cell to push to
for (unsigned int row = 0; row < sudoku.size(); row++) {
if (breaker == 2002) {
break;
}
for (unsigned int column = 0; column < sudoku.size(); column++) {
if (breaker == 2002) {
break;
}
if (sudoku[row][column] == 0) {
//choose option based on usage and then change usage list,worst case is the last value like with the change
int vectorpos = 0;
while (!isValidSingle(sudoku,usage[vectorpos][0]) && vectorpos != sudoku.size() - 1) {
++vectorpos;
}
//cout << usage[vectorpos][0] << " was pushed at " << row << column << endl;
sudoku[row][column] = usage[vectorpos][0];
usage[vectorpos][1] = usage[vectorpos][1] + 1;
sort(usage.begin(),sortcol2);
solution.push(make_pair(row,column));
breaker = 2002;
break;
}
}
}
}
//checks if we're at the end
if (solution.top().first == sudoku.size() - 1 && solution.top().second == sudoku.size() - 1){
solved = true;
}
//printSudoku(sudoku);
//prints out usage vector {not useful}
//printUsage(usage);
}
return 1;
}
bool isRowValid(vector <vector <int>> &sudoku,int possval) {
for (unsigned int i = 0; i < sudoku.size(); i++) {
if (possval == sudoku[row][i]) {
return false;
}
}
return true;
}
bool isColumnValid(vector <vector <int>> &sudoku,int possval) {
for (unsigned int j = 0; j < sudoku.size(); j++) {
if (possval == sudoku[j][column]) {
return false;
}
}
return true;
}
int assignBlock9x9(int pos) {
if (0 <= pos && pos <= 2) {
return 0;
}
else if (3 <= pos && pos <= 5) {
return 3;
}
else {
return 6;
}
}
int assignBlock16x16(int pos) {
if (0 <= pos && pos <= 3) {
return 0;
}
else if (4 <= pos && pos <= 7) {
return 4;
}
else if (8 <= pos && pos <= 11){
return 8;
}
else {
return 12;
}
}
int assignBlock25x25(int pos) {
if (0 <= pos && pos <= 4) {
return 0;
}
else if (5 <= pos && pos <= 9) {
return 5;
}
else if(10 <= pos && pos <= 14){
return 10;
}
else if (15 <= pos && pos <= 19) {
return 15;
}
else {
return 20;
}
}
bool isBlockValid(vector <vector <int>> &sudoku,int possval) {
//if 9x9
if (sudoku.size() == 9) {
int startrow = assignBlock9x9(row);
int startcolumn = assignBlock9x9(column);
for (int i = startrow; i <= startrow + 2; i++) {
for (int j = startcolumn; j <= startcolumn + 2; j++) {
if (possval == sudoku[i][j]) {
return false;
}
}
}
}
//if 16x16
else if (sudoku.size()==16) {
int startrow = assignBlock16x16(row);
int startcolumn = assignBlock16x16(column);
for (int i = startrow; i <= startrow + 3; i++) {
for (int j = startcolumn; j <= startcolumn + 3; j++) {
if (possval == sudoku[i][j]) {
return false;
}
}
}
}
//if 25x25
else {
int startrow = assignBlock25x25(row);
int startcolumn = assignBlock25x25(column);
for (int i = startrow; i <= startrow + 4; i++) {
for (int j = startcolumn; j <= startcolumn + 4; j++) {
if (possval == sudoku[i][j]) {
return false;
}
}
}
}
return true;
}
bool isValidSingle(vector <vector <int>> &sudoku,int possval) {
if (isRowValid(sudoku,possval) && isColumnValid(sudoku,possval) && isBlockValid(sudoku,possval)) {
return true;
}
return false;
}
bool isRowValid2(vector <vector <int>> &sudoku,int possval) {
int samecount = 0;
for (unsigned int i = 0; i < sudoku.size(); i++) {
if (sudoku[row][i] == possval) {
++samecount;
}
if (samecount == 2) {
return false;
}
}
return true;
}
bool isColumnValid2(vector <vector <int>> &sudoku,int possval) {
int samecount = 0;
for (unsigned int j = 0; j < sudoku.size(); j++) {
if (sudoku[j][column] == possval) {
++samecount;
}
if (samecount == 2) {
return false;
}
}
return true;
}
bool isBlockValid2(vector <vector <int>>& sudoku,int possval) {
int samecount = 0;
//if 9x9
if (sudoku.size() == 9) {
int startrow = assignBlock9x9(row);
int startcolumn = assignBlock9x9(column);
for (int i = startrow; i <= startrow + 2; i++) {
for (int j = startcolumn; j <= startcolumn + 2; j++) {
if (possval == sudoku[i][j]) {
++samecount;
}
if (samecount == 2) {
return false;
}
}
}
}
//if 16x16
else if (sudoku.size() == 16) {
int startrow = assignBlock16x16(row);
int startcolumn = assignBlock16x16(column);
for (int i = startrow; i <= startrow + 3; i++) {
for (int j = startcolumn; j <= startcolumn + 3; j++) {
if (possval == sudoku[i][j]) {
++samecount;
}
if (samecount == 2) {
return false;
}
}
}
}
//if 25x25
else {
int startrow = assignBlock25x25(row);
int startcolumn = assignBlock25x25(column);
for (int i = startrow; i <= startrow + 4; i++) {
for (int j = startcolumn; j <= startcolumn + 4; j++) {
if (possval == sudoku[i][j]) {
++samecount;
}
if (samecount == 2) {
return false;
}
}
}
}
return true;
}
bool isValidSingle2(vector <vector <int>> &sudoku,int possval) {
if (isRowValid2(sudoku,possval) && isColumnValid2(sudoku,possval) && isBlockValid2(sudoku,possval)) {
return true;
}
return false;
}
bool sortcol(const vector<int>& v1,const vector<int>& v2) {
return v1[1] < v2[1];
}
bool sortcol2(const vector<int>& v1,const vector<int>& v2) {
return v1[0] < v2[0] && v1[1] == v2[1];
}
vector <vector <int>> Usage(vector <vector <int>> &sudoku) {
vector <int> usage;
vector <vector <int>> usage2;
for (unsigned int i = 0; i < sudoku.size(); i++) {
usage.push_back(0);
}
for (unsigned int row = 0; row < sudoku.size(); row++) {
for (unsigned int column = 0; column < sudoku.size(); column++) {
if (sudoku[row][column] == 0) {
continue;
}
usage[sudoku[row][column] -1] = usage[sudoku[row][column] - 1] + 1;
}
}
for (unsigned int i = 1; i <= sudoku.size(); i++) {
usage2.push_back({(int) i,usage[i - 1] });
}
sort(usage2.begin(),usage2.begin() + usage2.size(),sortcol);
sort(usage2.begin(),sortcol2);
return usage2;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。