微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在C ++中使用堆栈和回溯在数独求解器上工作,需要帮​​助修复我的算法

如何解决在C ++中使用堆栈和回溯在数独求解器上工作,需要帮​​助修复我的算法

最初,我的算法涉及测试nxn数独的1-> n中的每个数字,但由于它无法解决16x16数独(算法运行了3个小时没有运气),我认为最好选择一个基于板上最有效和最少使用的编号的单元。我想我已经解决了大部分问题,例如我制作了一个二维矢量,称为用法(第一列是数字,第二列是用法),每次在板上进行更改时都会对其进行排序。现在,我可以解决一个简单的9x9和一个空的16x16,但是我在其他地方没有运气。想知道是否有人可以帮助我找出我缺乏逻辑的地方。

///我使用堆栈>存储我们放置了值的最新行和列。第一个int是行,第二个是列。

#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 举报,一经查实,本站将立刻删除。