用c++寫的效率低下的數獨解析
阿新 • • 發佈:2018-12-18
最近在刷leetcode,發現好多問題還挺有意思的。但是碰到問題,找不到更優的解決方法,按照自己的想法搞出來的方式效率有點低,碰到較為複雜的數獨就會嚴重超時導致沒有結果能出來。
先在這裡寫一個,後續優化之後再放出來。
#include <stdio.h> #include <stdlib.h> #include <vector> #include <string> #include <map> #ifdef WIN32 #include <Windows.h> #else #include <unistd.h>//getcwd #include <string.h>//memset #endif using namespace std; class Solution { public: void solveSudoku(vector<vector<char> >& board) { //2統計每行未出現的值 //3統計每格未出現的數字,如果某數字在該列只出現在某一行,那麼該數字必定只能出現在該位置 map<int, string> misColRowReversed;//每格可能出現的值彙總 for (int index = 0; index < 9; ++index) { for (int j = 0; j < 9; ++j) { misColRowReversed[index * 9 + j] = "123456789"; } } vector<vector<char> >::iterator vvcItor = board.begin(); for (int rowIndex = 0; vvcItor != board.end(); ++vvcItor, ++rowIndex) { vector<char>::iterator vcItor = vvcItor->begin(); for (int k = 0; vcItor != vvcItor->end(); ++vcItor, ++k) { if (*vcItor != '.') { for (int j = 0; j < 9; ++j) { //將已經出現的數字從每格保留值當中移除 int iFindIndex = 0; iFindIndex = misColRowReversed[rowIndex * 9 + j].find(*vcItor); if (iFindIndex != string::npos) { misColRowReversed[rowIndex * 9 + j].erase(iFindIndex, 1); } iFindIndex = misColRowReversed[j * 9 + k].find(*vcItor); if (iFindIndex != string::npos) { misColRowReversed[j * 9 + k].erase(iFindIndex, 1); } } misColRowReversed[rowIndex * 9 + k] = ""; misColRowReversed[rowIndex * 9 + k] += *vcItor; } } } // bool bOver = false; while (1) { if (bOver) { break; } bOver = true; int rowIndex4 = 0; for (vvcItor = board.begin(); vvcItor != board.end(); ++vvcItor, ++rowIndex4) { map<int, string> misColSum; misColSum.clear(); //如果一行當中,某個值在一個位置出現,那麼這個值只能出現在該位置。與此同時,當前行和列種應移除該值。 vector<char>::iterator itor = vvcItor->begin(); for (int jColIndex = 0; itor != vvcItor->end(); ++itor, ++jColIndex) { //彙總每列所有可能出現的值 string colStr = ""; for (int kRowIndex = 0; kRowIndex < 9; ++kRowIndex) { if (misColRowReversed[kRowIndex * 9 + jColIndex].length() > 1) { colStr += misColRowReversed[kRowIndex * 9 + jColIndex]; } } map<char, int> mci; mci.clear(); for (int i = 0; i < 9; ++i) { mci['1' + i] = 0; } for (int i = 0; i < colStr.length(); ++i) { mci[colStr[i]]++; } char ch; for (map<char, int>::iterator mciItor = mci.begin(); mciItor != mci.end(); ++mciItor) { //某值只可能出現一次,那麼這個值就只能出現在該位置 if (mciItor->second == 1) { ch = mciItor->first; for (int kRowIndex = 0; kRowIndex < 9; ++kRowIndex) { int iPos = 0; if (misColRowReversed[kRowIndex * 9 + jColIndex].length() > 1 && (iPos = misColRowReversed[kRowIndex * 9 + jColIndex].find(ch)) != string::npos) { misColRowReversed[kRowIndex * 9 + jColIndex] = ""; misColRowReversed[kRowIndex * 9 + jColIndex] += ch; //當前行 kRowIndex 的所有列應該移除包含ch的內容 for (int lColIndex = 0; lColIndex < 9; ++lColIndex) { if (misColRowReversed[kRowIndex * 9 + lColIndex].length() > 1 && (iPos = misColRowReversed[kRowIndex * 9 + lColIndex].find(ch)) != string::npos) { misColRowReversed[kRowIndex * 9 + lColIndex].erase(iPos, 1); } } } } } } //如果一個點沒值,而這個點可能出現的值只有一個,那麼該值肯定只能在該位置。 //這個值寫入之後,對應行和列的保留值當中,需要移除該值。 if (*itor == '.' && misColRowReversed[rowIndex4 * 9 + jColIndex].length() == 1) { bOver = false; *itor = misColRowReversed[rowIndex4 * 9 + jColIndex][0]; for (int i = 0; i < 9; ++i) { if (misColRowReversed[i * 9 + jColIndex].length() > 1) { int iIndex = misColRowReversed[i * 9 + jColIndex].find(*itor); if (iIndex != string::npos) { misColRowReversed[i * 9 + jColIndex].erase(iIndex, 1); } } } } } } } //計算出每行可能出現哪些填充排列 map<int, vector<string> > mivsRow;//儲存每一行可能出現的排列組合都有哪些 mivsRow.clear(); for (int row = 0; row < 9; ++row) { vector<string> vstr; vstr.clear(); vector<string> vstrValidNums; vstrValidNums.clear(); for (int iCol = 0; iCol < 9; ++iCol) { if (misColRowReversed[row * 9 + iCol].length() > 1) { vstrValidNums.push_back(misColRowReversed[row * 9 + iCol]); } } GenerateArray(vstrValidNums, vstr); mivsRow[row] = vstr; } //遍歷數獨的每行,並用mivsRow的對應行去填充每行為'.'處,倘若填充之後為合法數獨,則停止。 //否則重新填充。 vector<string>::iterator row1Itor; vector<string>::iterator row2Itor; vector<string>::iterator row3Itor; vector<string>::iterator row4Itor; vector<string>::iterator row5Itor; vector<string>::iterator row6Itor; vector<string>::iterator row7Itor; vector<string>::iterator row8Itor; vector<string>::iterator row9Itor; vector<vector<char> > vvc(board); vector<vector<char> > vvcTemp; vvcTemp.clear(); for (row1Itor = mivsRow[0].begin(); row1Itor != mivsRow[0].end(); ++row1Itor) { vector<vector<char> >::iterator rowItor = vvc.begin(); int row1ColIndex = 0; vector<char> vcTemp; for (vector<char>::iterator itor1 = (*rowItor).begin(); itor1 != (*rowItor).end(); ++itor1) { if (*itor1 == '.') { vcTemp.push_back((*row1Itor)[row1ColIndex]); ++row1ColIndex; } else { vcTemp.push_back(*itor1); } } vvcTemp.push_back(vcTemp); if (!isValidSudoku(vvcTemp)) { vvcTemp.pop_back(); continue; } ++rowItor; for (row2Itor = mivsRow[1].begin(); row2Itor != mivsRow[1].end(); ++row2Itor) { int row2ColIndex = 0; vcTemp.clear(); for (vector<char>::iterator itor2 = (*rowItor).begin(); itor2 != (*rowItor).end(); ++itor2) { if (*itor2 == '.') { vcTemp.push_back((*row2Itor)[row2ColIndex]); ++row2ColIndex; } else { vcTemp.push_back(*itor2); } } vvcTemp.push_back(vcTemp); if (!isValidSudoku(vvcTemp)) { vvcTemp.pop_back(); continue; } ++rowItor; for (row3Itor = mivsRow[2].begin(); row3Itor != mivsRow[2].end(); ++row3Itor) { int row3ColIndex = 0; vcTemp.clear(); for (vector<char>::iterator itor3 = (*rowItor).begin(); itor3 != (*rowItor).end(); ++itor3) { if (*itor3 == '.') { vcTemp.push_back((*row3Itor)[row3ColIndex]); ++row3ColIndex; } else { vcTemp.push_back(*itor3); } } vvcTemp.push_back(vcTemp); if (!isValidSudoku(vvcTemp)) { vvcTemp.pop_back(); continue; } ++rowItor; for (row4Itor = mivsRow[3].begin(); row4Itor != mivsRow[3].end(); ++row4Itor) { int row4ColIndex = 0; vcTemp.clear(); for (vector<char>::iterator itor4 = (*rowItor).begin(); itor4 != (*rowItor).end(); ++itor4) { if (*itor4 == '.') { vcTemp.push_back((*row4Itor)[row4ColIndex]); ++row4ColIndex; } else { vcTemp.push_back(*itor4); } } vvcTemp.push_back(vcTemp); if (!isValidSudoku(vvcTemp)) { vvcTemp.pop_back(); continue; } ++rowItor; for (row5Itor = mivsRow[4].begin(); row5Itor != mivsRow[4].end(); ++row5Itor) { int row5ColIndex = 0; vcTemp.clear(); for (vector<char>::iterator itor5 = (*rowItor).begin(); itor5 != (*rowItor).end(); ++itor5) { if (*itor5 == '.') { vcTemp.push_back((*row5Itor)[row5ColIndex]); ++row5ColIndex; } else { vcTemp.push_back(*itor5); } } vvcTemp.push_back(vcTemp); if (!isValidSudoku(vvcTemp)) { vvcTemp.pop_back(); continue; } ++rowItor; for (row6Itor = mivsRow[5].begin(); row6Itor != mivsRow[5].end(); ++row6Itor) { int row6ColIndex = 0; vcTemp.clear(); for (vector<char>::iterator itor6 = (*rowItor).begin(); itor6 != (*rowItor).end(); ++itor6) { if (*itor6 == '.') { vcTemp.push_back((*row6Itor)[row6ColIndex]); ++row6ColIndex; } else { vcTemp.push_back(*itor6); } } vvcTemp.push_back(vcTemp); if (!isValidSudoku(vvcTemp)) { vvcTemp.pop_back(); continue; } ++rowItor; for (row7Itor = mivsRow[6].begin(); row7Itor != mivsRow[6].end(); ++row7Itor) { int row7ColIndex = 0; vcTemp.clear(); for (vector<char>::iterator itor7 = (*rowItor).begin(); itor7 != (*rowItor).end(); ++itor7) { if (*itor7 == '.') { vcTemp.push_back((*row7Itor)[row7ColIndex]); ++row7ColIndex; } else { vcTemp.push_back(*itor7); } } vvcTemp.push_back(vcTemp); if (!isValidSudoku(vvcTemp)) { vvcTemp.pop_back(); continue; } ++rowItor; for (row8Itor = mivsRow[7].begin(); row8Itor != mivsRow[7].end(); ++row8Itor) { int row8ColIndex = 0; vcTemp.clear(); for (vector<char>::iterator itor8 = (*rowItor).begin(); itor8 != (*rowItor).end(); ++itor8) { if (*itor8 == '.') { vcTemp.push_back((*row8Itor)[row8ColIndex]); ++row8ColIndex; } else { vcTemp.push_back(*itor8); } } vvcTemp.push_back(vcTemp); if (!isValidSudoku(vvcTemp)) { vvcTemp.pop_back(); continue; } ++rowItor; for (row9Itor = mivsRow[8].begin(); row9Itor != mivsRow[8].end(); ++row9Itor) { int row9ColIndex = 0; vcTemp.clear(); for (vector<char>::iterator itor9 = (*rowItor).begin(); itor9 != (*rowItor).end(); ++itor9) { if (*itor9 == '.') { vcTemp.push_back((*row9Itor)[row9ColIndex]); ++row9ColIndex; } else { vcTemp.push_back(*itor9); } } vvcTemp.push_back(vcTemp); if (isValidSudoku(vvcTemp)) { board = vvcTemp; return; } else { vvcTemp.pop_back(); continue; } } vvcTemp.pop_back(); --rowItor; } vvcTemp.pop_back(); --rowItor; } vvcTemp.pop_back(); --rowItor; } vvcTemp.pop_back(); --rowItor; } vvcTemp.pop_back(); --rowItor; } vvcTemp.pop_back(); --rowItor; } vvcTemp.pop_back(); --rowItor; } vvcTemp.pop_back(); --rowItor; } } void GenerateArray(vector<string> vArray, vector<string> &vResult) { vector<string>::iterator itor = vArray.begin(); for (; itor != vArray.end(); ++itor) { GenerateArray(*itor, vResult); } } void GenerateArray(string str, vector<string>& vStr) { vector<string> vTemp; vTemp.clear(); if (vStr.empty()) { for (size_t index = 0; index < str.length(); ++index) { string s = ""; s += str[index]; vTemp.push_back(s); } } for (vector<string>::iterator itor = vStr.begin(); itor != vStr.end(); ++itor) { for (size_t index = 0; index < str.length(); ++index) { if ((*itor).find(str[index]) != string::npos) continue; string s = *itor; s += str[index]; vTemp.push_back(s); } } vStr.clear(); for (vector<string>::iterator itor = vTemp.begin(); itor != vTemp.end(); ++itor) { vStr.push_back(*itor); } } bool isValidSudoku(vector<vector<char> >& vvc) { vector<vector<char> >::iterator vvItor = vvc.begin(); //如果一行當中出現兩個相同的數字,肯定是不合法的數獨 //如果一列當中出現兩個相同的數字,也肯定是不合法的數獨 map<int, string> mColInfo; //每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; } } } return true; } }; string GetCurrentModuleAddr() { char chPath[256] = { 0 }; #ifdef WIN32 GetModuleFileNameA(NULL, chPath, 256); printf("%s\n", chPath); #else getcwd(chPath, 256); printf("%s\n", chPath); #endif string sPath(chPath); #ifdef WIN32 int iPos = sPath.find_last_of('\\'); if (iPos != string::npos) { sPath = sPath.substr(0, iPos + 1); } else if ((iPos = sPath.find_last_of('/')) != string::npos) { sPath = sPath.substr(0, iPos + 1); } else { return ""; } #else sPath += "/"; #endif return sPath; } int main(int argc, char **argv) { vector<string> vStr; //之前6m25.284s 現在0m12.740s //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"); //入門數獨 //0m0.026s //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.."); //初級 2m9.907s 0m36.374s //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"); //中級 超時 //vStr.push_back(".....9..3"); //vStr.push_back("........."); //vStr.push_back("58......."); //vStr.push_back("........."); //vStr.push_back("...2..65."); //vStr.push_back(".93..7..."); //vStr.push_back(".2.54..8."); //vStr.push_back("..1.....7"); //vStr.push_back("...6....."); //中級 0m3.284s //vStr.push_back("...5...82"); //vStr.push_back(".6..7.9.."); //vStr.push_back("9.5......"); //vStr.push_back("6.39.274."); //vStr.push_back(".146..3.."); //vStr.push_back("..9..35.6"); //vStr.push_back("72...5..."); //vStr.push_back("......25."); //vStr.push_back("..8.4...7"); string sPath = GetCurrentModuleAddr(); if (sPath.empty()) { printf("cann't get file path\n"); return -1; } FILE *fp; fp = fopen(string(sPath + "sudoku.txt").c_str(), "r"); if (!fp) { printf("cann't open sudoku.txt!\n"); return -1; } char *chBuff = new char[20]; memset(chBuff, 0, 20); while (fgets(chBuff, 19, fp) != NULL) { string str(chBuff); str.erase(str.length() - 1, 1); vStr.push_back(str); } fclose(fp); //高階 20170704 超時 //vStr.push_back("6.......7"); //vStr.push_back(".....3..."); //vStr.push_back(".7...1..."); //vStr.push_back("......13."); //vStr.push_back("......8.."); //vStr.push_back("4..69...."); //vStr.push_back(".857....."); //vStr.push_back("...4....2"); //vStr.push_back(".3......."); //高階 20170702 0m0.111s //vStr.push_back("2.54.7..."); //vStr.push_back("1478...2."); //vStr.push_back("..3..5..."); //vStr.push_back(".......82"); //vStr.push_back("52..9.7.6"); //vStr.push_back("764.8239."); //vStr.push_back("9..6..25."); //vStr.push_back("..6....3."); //vStr.push_back(".5..396.4"); //高階 20170701 超時 //vStr.push_back(".7...1..."); //vStr.push_back("...6..5.8"); //vStr.push_back("......4.."); //vStr.push_back("1....7.9."); //vStr.push_back("..4......"); //vStr.push_back("....3...."); //vStr.push_back("....5...."); //vStr.push_back("...4...2."); //vStr.push_back("79.....1."); 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"); } system("pause"); return 0; }