1. 程式人生 > >繼上一篇部落格之後,對數獨解析方式進行了優化更新。

繼上一篇部落格之後,對數獨解析方式進行了優化更新。

#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <string>
#include <map>

using namespace std;

void PrintVector(vector<vector<char> > &vvc)
{
    printf("---\n");
    for (vector<vector<char> >::iterator itor = vvc.begin();
        itor != vvc.end(); ++itor)
    {
        for (vector<char>::iterator vcItor = itor->begin();
            vcItor != itor->end(); ++vcItor)
        {
            printf("%c ", *vcItor);
        }
        printf("\n");
    }
}

#define MAX_LENGTH 9

class Solution {
public:
    void solveSudoku(vector<vector<char> >& board) {
        //統計每點未出現的數字,如果某數字在該列只出現在某一行,那麼該數字必定只能出現在該位置
        vector<vector<char> > vvcTemp(board);
        map<int, string> misColRowExisted;//3*3 existed
        map<int, string> misDotReversed;
        for (int irow = 0; irow < MAX_LENGTH; ++irow)
        {
            for (int icol = 0; icol < MAX_LENGTH; ++icol)
            {
                misDotReversed[irow * MAX_LENGTH + icol] = "123456789";
            }
        }

        int rowIndex = 0;
        for (vector<vector<char> >::iterator itor = vvcTemp.begin(); itor != vvcTemp.end(); ++itor, ++rowIndex)
        {
            int colIndex = 0;
            for (vector<char>::iterator colItor = itor->begin(); colItor != itor->end(); ++colItor, ++colIndex)
            {
                if (*colItor != '.')
                {
                    misColRowExisted[rowIndex / 3 * 3 + colIndex / 3] += *colItor;
                }
            }
        }

        for (int row = 0; row < MAX_LENGTH; ++row)
        {
            for (int col = 0; col < MAX_LENGTH; ++col)
            {
                if (misDotReversed[row * MAX_LENGTH + col].length() > 1)
                {
                    for (int iLength = 0; iLength < misColRowExisted[row / 3 * 3 + col / 3].length(); ++iLength)
                    {
                        int iFindIndex = 0;
                        if ((iFindIndex =
                            misDotReversed[row * 9 + col].find(\
                                misColRowExisted[row / 3 * 3 + col / 3][iLength]))
                            != string::npos)
                        {
                            misDotReversed[row * 9 + col].erase(iFindIndex, 1);
                        }
                    }
                }

            }
        }

        int iRowIndex = 0;
        for (vector<vector<char> >::iterator itor = vvcTemp.begin(); itor != vvcTemp.end(); ++itor, ++iRowIndex)
        {
            int iColIndex = 0;
            for (vector<char>::iterator itor2 = itor->begin(); itor2 != itor->end(); ++itor2, ++iColIndex)
            {
                if (*itor2 != '.')
                {
                    for (int icol = 0; icol < MAX_LENGTH; ++icol)
                    {
                        //移除當前行所有包含該值的列的內容
                        int iPos = misDotReversed[iRowIndex * MAX_LENGTH + icol].find(*itor2);
                        if (iPos != string::npos)
                        {
                            misDotReversed[iRowIndex * MAX_LENGTH + icol].erase(iPos, 1);
                        }

                        //移除所有行在當前列包含該值的內容
                        iPos = misDotReversed[icol * MAX_LENGTH + iColIndex].find(*itor2);
                        if (iPos != string::npos)
                        {
                            misDotReversed[icol * MAX_LENGTH + iColIndex].erase(iPos, 1);
                        }
                    }

                    misDotReversed[iRowIndex * MAX_LENGTH + iColIndex] = *itor2;
                }
            }
        }

        bool bEnd = false;
        while (1)
        {
            if (bEnd)
            {
                break;
            }

            bEnd = true;

            iRowIndex = 0;
            for (vector<vector<char> >::iterator itor = vvcTemp.begin(); itor != vvcTemp.end(); ++itor, ++iRowIndex)
            {
                int iColIndex = 0;
                for (vector<char>::iterator itor2 = itor->begin(); itor2 != itor->end(); ++itor2, ++iColIndex)
                {
                    if (*itor2 == '.' && misDotReversed[iRowIndex * MAX_LENGTH + iColIndex].length() == 1)
                    {
                        bEnd = false;
                        *itor2 = misDotReversed[iRowIndex * MAX_LENGTH + iColIndex][0];

                        for (int j = 0; j < MAX_LENGTH; ++j)
                        {
                            int iPos = 0;
                            //從當前行的所有列當中包含該值的保留值內容中移除該值
                            if (misDotReversed[iRowIndex * MAX_LENGTH + j].length() > 1 &&
                                (iPos = misDotReversed[iRowIndex * MAX_LENGTH + j].find(*itor2)) != string::npos)
                            {
                                misDotReversed[iRowIndex * MAX_LENGTH + j].erase(iPos, 1);
                            }

                            //從當前列的所有行保留值當中包含該值的內容中移除該值
                            if (misDotReversed[j * MAX_LENGTH + iColIndex].length() > 1 &&
                                (iPos = misDotReversed[j * MAX_LENGTH + iColIndex].find(*itor2)) != string::npos)
                            {
                                misDotReversed[j * MAX_LENGTH + iColIndex].erase(iPos, 1);
                            }
                        }
                    }
                }
            }
        }

        map<int, vector<string> > misRowReversed;
        for (int temp = 0; temp < MAX_LENGTH; ++temp)
        {
            for (int jTemp = 0; jTemp < MAX_LENGTH; ++jTemp)
            {
                if (misDotReversed[temp * MAX_LENGTH + jTemp].length() > 1)
                {
                    misRowReversed[temp].push_back(misDotReversed[temp * MAX_LENGTH + jTemp]);
                }
            }
        }

        //從每格可能出現的值當中組成字串,以此進行匹配
        //(12) (45)-> 14 15 24 25這種,而不是用排列組合進行匹配

        map<int, vector<string> > misRowInfo;
        misRowInfo.clear();
        for (int index = 0; index < 9; ++index)
        {
            vector<string> vstr;
            GenerateArray(misRowReversed[index], vstr);
            misRowInfo[index] = vstr;
        }

        //遍歷數獨的每行,並用misRowInfo的對應行去填充每行為'.'處,倘若填充之後為合法數獨,則停止。
        //否則重新填充。
        vector<vector<char> > vvc(vvcTemp);
        vector<vector<char> > vvcTemp2;
        vvcTemp2.clear();
        //
        map<int, vector<string>::iterator> mItor;
        for (int i = 0; i < MAX_LENGTH; ++i)
        {
            mItor[i] = misRowInfo[i].begin();
        }
        vector<vector<char> >::iterator rowItor = vvc.begin();
        bool bNeedRecalc = false;
        vector<int> viNeedRecalcRowIndex;
        for (int rowIndex = 0; rowItor != vvc.end();)
        {
            if (!misRowInfo[rowIndex].empty() && mItor[rowIndex] == misRowInfo[rowIndex].end())
            {
                if (0 == rowIndex)
                {
                    return;
                }

                mItor[rowIndex] = misRowInfo[rowIndex].begin();
                vvcTemp2.pop_back();
                --rowItor;
                --rowIndex;
                continue;
            }
            vector<char> vctemp;
            int colIndex = 0;
            for (vector<char>::iterator colItor = rowItor->begin(); colItor != rowItor->end(); ++colItor)
            {
                if ((*colItor) == '.')
                {
                    vctemp.push_back((*(mItor[rowIndex]))[colIndex]);
                    ++colIndex;
                }
                else
                {
                    vctemp.push_back(*colItor);
                }
            }
            vvcTemp2.push_back(vctemp);
            if (!isValidSudoku(vvcTemp2))
            {
                vvcTemp2.pop_back();
                //如果當前行的所有值全都確定,那麼misRowInfo[rowIndex]必定是空的,所以如果數獨非法,必定是該行的上一行有問題
                if (misRowInfo[rowIndex].empty())
                {
                    for (int i = rowIndex; i >= 0; --i)
                    {
                        if (misRowInfo[i].empty())
                        {
                            vvcTemp2.pop_back();
                            if (rowItor != vvc.begin())
                            {
                                --rowIndex;
                                --rowItor;
                            }
                            continue;
                        }
                        else
                        {
                            if (mItor[i] != misRowInfo[i].end())
                                ++mItor[i];
                            if (mItor[i] == misRowInfo[i].end())
                            {
                                if (0 == rowIndex)
                                    return;
                                for (int j = rowIndex; j >= 0; --j)
                                {
                                    mItor[j] = misRowInfo[j].begin();
                                    vvcTemp2.pop_back();
                                    --rowItor;
                                    --rowIndex;
                                }
                            }
                            break;
                        }
                    }
                    continue;
                }
                if (mItor[rowIndex] != misRowInfo[rowIndex].end())
                    ++mItor[rowIndex];
                if (mItor[rowIndex] == misRowInfo[rowIndex].end())
                {
                    if (0 == rowIndex)
                    {
                        return;
                    }

                    for (int i = rowIndex; i < MAX_LENGTH; ++i)
                    {
                        mItor[i] = misRowInfo[i].begin();
                    }
                    vvcTemp2.pop_back();
                    --rowIndex;
                    --rowItor;
                }
                continue;
            }
            //PrintVector(vvcTemp2);
            if (!misRowInfo[rowIndex].empty())
            {
                ++mItor[rowIndex];
                if (mItor[rowIndex] == misRowInfo[rowIndex].end())
                {
                    bool bContinue = false;
                    vector<int>::iterator reCalcItor = viNeedRecalcRowIndex.end();
                    if (!viNeedRecalcRowIndex.empty())
                    {
                        --reCalcItor;
                        if (*reCalcItor == rowIndex)
                        {
                            viNeedRecalcRowIndex.erase(reCalcItor);
                            if (!vvcTemp2.empty())
                                vvcTemp2.pop_back();
                            if (!vvcTemp2.empty())
                                vvcTemp2.pop_back();
                            if (rowItor != vvc.begin())
                            {
                                --rowItor;
                                --rowIndex;
                            }
                            bContinue = true;
                        }
                    }

                    if (bContinue)
                        continue;

                    viNeedRecalcRowIndex.push_back(rowIndex);
                    for (int i = rowIndex + 1; i < MAX_LENGTH; ++i)
                    {
                        mItor[i] = misRowInfo[i].begin();
                    }

                    --mItor[rowIndex];
                }
            }
            ++rowItor;
            ++rowIndex;
        }

        board = vvcTemp2;
    }

    void GenerateArray(vector<string > &vStr, vector<string> &vResult)
    {
        for (vector<string>::iterator itor = vStr.begin();
            itor != vStr.end(); ++itor)
        {
            if (vResult.empty())
            {
                for (int iLength = 0; iLength < (*itor).length(); ++iLength)
                {
                    string s = "";
                    s += (*itor)[iLength];
                    vResult.push_back(s);
                }
            }
            else
            {
                vector<string> vTemp;
                vTemp.clear();
                for (vector<string>::iterator resItor = vResult.begin();
                    resItor != vResult.end(); ++resItor)
                {
                    for (int iLength = 0; iLength < (*itor).length(); ++iLength)
                    {
                        if ((*resItor).find((*itor)[iLength]) == string::npos)
                            vTemp.push_back(*resItor + (*itor)[iLength]);
                    }
                }

                vResult.clear();
                vResult = vTemp;
            }
        }
    }

    bool isValidSudoku(vector<vector<char> >& vvc)
    {
        vector<vector<char> >::iterator vvItor = vvc.begin();
        //如果一行當中出現兩個相同的數字,肯定是不合法的數獨
        //如果一列當中出現兩個相同的數字,也肯定是不合法的數獨
        map<int, string> mColInfo;
        map<int, string> mRowInfo;
        //每9個小格數字統計,9個小格數字也不能有重複
        map<int, string> mColRowInfo;
        map<int, int> mRowReversed;
        map<int, int> mColReversed;
        for (int index = 0; index < 9; ++index)
        {
            mRowReversed[index] = 0;
            mColReversed[index] = 0;
        }

        for (int i = 0; vvItor != vvc.end(); ++vvItor, ++i)
        {
            vector<char>::iterator vItor = vvItor->begin();
            string sRow = "";
            for (int k = 0; vItor != vvItor->end(); ++vItor, ++k)
            {
                if (*vItor != '.')
                {
                    if (sRow.find(*vItor) != string::npos)
                        return false;
                    else
                        sRow += *vItor;

                    if (mColInfo[k].find(*vItor) != string::npos)
                        return false;
                    else
                        mColInfo[k] += *vItor;

                    //81個數字共分為9個小格,小格的編號計算方式 列號/3+行號/3*3
                    //int j = k/3 + i/3*3;
                    if (mColRowInfo[k/3 + i/3*3].find(*vItor) != string::npos)
                        return false;
                    else
                        mColRowInfo[k/3 + i/3*3] += *vItor;
                }

                if (*vItor == '.')
                {
                    mRowReversed[i] += 1;
                    mColReversed[k] += 1;
                }
            }
            mRowInfo[i] = sRow;
        }

        return true;
    }
};

int main(int argc, char **argv)
{
    vector<string> vStr;

    //入門數獨  0m0.023s
    vStr.push_back("..5..1627");
    vStr.push_back(".6.347158");
    vStr.push_back("71.6.2.93");
    vStr.push_back("..3218746");
    vStr.push_back(".7.439582");
    vStr.push_back("8245..9.1");
    vStr.push_back("4891...75");
    vStr.push_back("231795864");
    vStr.push_back(".578243..");

    //初級  115m16.032s
    //vStr.push_back("....6.3..");
    //vStr.push_back(".74.....8");
    //vStr.push_back("..2......");
    //vStr.push_back("..9....4.");
    //vStr.push_back("2...5....");
    //vStr.push_back("....3....");
    //vStr.push_back("3.18.....");
    //vStr.push_back("...4...2.");
    //vStr.push_back("......5..");

    //0m43.788s  ->  0m2.590s
    //vStr.push_back("..421.8.3");
    //vStr.push_back("..6......");
    //vStr.push_back(".7.9.....");
    //vStr.push_back(".........");
    //vStr.push_back("1.2.435..");
    //vStr.push_back("...6.79..");
    //vStr.push_back(".......4.");
    //vStr.push_back(".35.....9");
    //vStr.push_back("....3.1.8");

    //*********************
    //藍天5級 高階 0m30.763s  ->  0m0.795s
    //vStr.push_back(".........");
    //vStr.push_back(".94.3..1.");
    //vStr.push_back("...2.9.5.");
    //vStr.push_back("..89.32..");
    //vStr.push_back(".3..7..9.");
    //vStr.push_back("..71.58..");
    //vStr.push_back(".6.8.4...");
    //vStr.push_back(".7..6.98.");
    //vStr.push_back(".........");

    //藍天6級 超高階 0m29.257s  ->  0m2.254s
    //vStr.push_back("...3..2..");
    //vStr.push_back(".2....5.3");
    //vStr.push_back("..45..1.7");
    //vStr.push_back(".5..13...");
    //vStr.push_back("....4....");
    //vStr.push_back("...78..3.");
    //vStr.push_back("4.5..68..");
    //vStr.push_back("2.8....6.");
    //vStr.push_back("..7..2...");

    //0m6.672s  ->  0m0.281s
     //vStr.push_back(".3....96.");
     //vStr.push_back("1....6..3");
     //vStr.push_back("4..1.....");
     //vStr.push_back(".1..3.7..");
     //vStr.push_back("...5.4...");
     //vStr.push_back("..8.7..2.");
     //vStr.push_back(".....2..6");
     //vStr.push_back("9..8....2");
     //vStr.push_back(".82....5.");

     //vStr.push_back("53..7....");
     //vStr.push_back("6..195...");
     //vStr.push_back(".98....6.");
     //vStr.push_back("8...6...3");
     //vStr.push_back("4..8.3..1");
     //vStr.push_back("7...2...6");
     //vStr.push_back(".6....28.");
     //vStr.push_back("...419..5");
     //vStr.push_back("....8..79");
     //6m25.284s ->  0m0.024s

    //0m18.263s  ->  0m1.999s
    //vStr.push_back(".........");
    //vStr.push_back(".63...95.");
    //vStr.push_back(".8.13..2.");
    //vStr.push_back("...6.27..");
    //vStr.push_back("..5.7.6..");
    //vStr.push_back("..73.4...");
    //vStr.push_back(".5..89.3.");
    //vStr.push_back(".12...89.");
    //vStr.push_back(".........");

    vector<vector<char> > vvChar;
    vector<char> vChar;
    for (vector<string>::iterator itor = vStr.begin(); itor != vStr.end(); ++itor)
    {
        vChar.clear();
        for (size_t index = 0; index < (*itor).length(); ++index)
        {
            vChar.push_back((*itor)[index]);
        }
        vvChar.push_back(vChar);
    }

    for (vector<vector<char> >::iterator itor = vvChar.begin(); itor != vvChar.end(); ++itor)
    {
        vector<char>::iterator itor2 = itor->begin();
        for (; itor2 != itor->end(); ++itor2)
        {
            printf("%c ", *itor2);
        }
        printf("\n");
    }

    Solution sl;
    sl.solveSudoku(vvChar);

    printf("========================================\n");

    for (vector<vector<char> >::iterator itor = vvChar.begin(); itor != vvChar.end(); ++itor)
    {
        vector<char>::iterator itor2 = itor->begin();
        for (; itor2 != itor->end(); ++itor2)
        {
            printf("%c ", *itor2);
        }
        printf("\n");
    }

    return 0;
}