繼上一篇部落格之後,對數獨解析方式進行了優化更新。
阿新 • • 發佈:2018-12-18
#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; }