Головоломка 8 тайлов через BFS

Я искал глубины интернета, и мне еще предстоит найти решение моей проблемы. Я реализовал (я думаю) BFS для игры со скользящей плиткой. Тем не менее, он не может решить проблему, если состояние находится в нескольких шагах, иначе это просто приводит к ошибкам нехватки памяти.
Итак, мой вопрос к вам, где я иду не так? AFAIK мой код следует псевдокоду BFS.

РЕДАКТИРОВАТЬ / ПРИМЕЧАНИЕ: я прошел с отладчиком и до сих пор не нашел ничего необычного на мой взгляд, но я сравнительно начинающий программист.

#include <ctime>
#include <string>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <deque>
#include <vector>

using namespace std;

///////////////////////////////////////////////////////////////////////////////////////////
//
// Search Algorithm:  Breadth-First Search
//
// Move Generator:
//
////////////////////////////////////////////////////////////////////////////////////////////
class State{
public:
int state[9];

State(){
for (int i = 0; i < 9; i++){
state[i] = i;
}
}

State(string st){
for (int i = 0; i < st.length(); i++){
state[i] = st.at(i) - '0';
}
}

State(const State &st){
for (int i = 0; i < 9; i++){
state[i] = st.state[i];
}
}

bool operator==(const State& other) {

for (int i = 0; i < 9; i++){
if (this->state[i] != other.state[i]){return false;}
}
return true;
}

bool operator!=(const State& other) {
return !(*this == other);
}

void swap(int x, int y){
// State b; // blank state
// for (int i = 0; i < 9; i++) // fill blank state with current state
//  b.state[i] = state[i];

int t = this->state[x]; // saves value of the value in position x of the state

this->state[x] = this->state[y]; // swaps value of position x with position y in the state
this->state[y] = t; // swaps value of position y with saved position x in the state
}

int findBlank(){ // finds position in 3x3 of blank tile
for (int i=0; i<9; i++){
if (state[i]==0) return i;
}
}

vector<State> blankExpand(){
int pos = this->findBlank();
vector<State> vecStates;if (pos != 0 && pos != 1 && pos != 2){ // swaps the tile above it
State newState = State(*this);
newState.swap(pos,pos - 3);
vecStates.push_back(newState);
}

if (pos != 6 && pos != 7 && pos != 8){ // swaps the tile above it
State newState = State(*this);
newState.swap(pos,pos + 3);
vecStates.push_back(newState);
}

if (pos != 0 && pos != 3 && pos != 6){ // swaps the tile above it
State newState = State(*this);
newState.swap(pos,pos - 1);
vecStates.push_back(newState);
}

if (pos != 2 && pos != 5 && pos != 8){ // swaps the tile above it
State newState = State(*this);
newState.swap(pos,pos + 1);
vecStates.push_back(newState);
}

return vecStates;
}
};

string breadthFirstSearch_with_VisitedList(string const initialState, string const goalState){
string path;

clock_t startTime;
startTime = clock();

deque<State> nodesToVisit;
vector<State> visitedList;
int maxQLength = 0;//Init
State init(initialState);
State goal(goalState);
nodesToVisit.push_back(init);

int count = 0;
int numOfStateExpansions = 0 ;
//
while (!nodesToVisit.empty()){
if(maxQLength < nodesToVisit.size()){maxQLength = nodesToVisit.size();}

State cur = nodesToVisit.front();
nodesToVisit.pop_front();
//remove front

if (cur == goal){
//solution found
cout << "solved!";
break;
}

//Get children
vector<State> children = cur.blankExpand();

numOfStateExpansions += children.size();

//For each child
for (State& child : children) {
for (int i = 0 ; i < 9;i++){
cout << child.state[i];
}
cout << " child" << endl;

//If already visited ignore
if (std::find(visitedList.begin(), visitedList.end(), child) != visitedList.end()) {
// cout << "duplicate" << endl;
continue;
}

//If not in nodes to Visit
else if (std::find(nodesToVisit.begin(), nodesToVisit.end(), child) == nodesToVisit.end()) {
//Add child
nodesToVisit.push_back(child);
}
}
visitedList.push_back(cur);

}//***********************************************************************************************************
clock_t actualRunningTime = ((float)(clock() - startTime)/CLOCKS_PER_SEC);
return path;

}

int main(){
breadthFirstSearch_with_VisitedList("042158367", "123804765");
//042158367
}

// 0 4 2
// 1 5 8
// 3 6 7

0

Решение

В вашем коде есть ряд недостатков, которые замедляют его. Я действительно удивлен, что у вас хватило терпения дождаться, пока он достигнет состояния нехватки памяти.

Основными виновниками являются поиски:

std::find(visitedList.begin(), visitedList.end(), child) != visitedList.end()
//and
std::find(nodesToVisit.begin(), nodesToVisit.end(), child) == nodesToVisit.end()

Оба из них выполняются в O (N), что звучит нормально, но так как вы выполняете их на каждом узле, это приводит к O (N)2).

Вы можете исправить это с помощью std::unordered_set<> для visitedList, Кроме того, вы можете добавить узлы к visited_list как только вы поставите их в очередь (вместо того, чтобы вывести их в очередь). Таким образом, у вас будет только один поиск.

Нотабене Вам придется специализироваться std::hash<State> для того, чтобы использовать std::unordered_set,

Еще один намек: эти cout << ... в вашем основном цикле действительно замедляет работу, потому что они по умолчанию принудительно сбрасываются и синхронизируются с ОС, комментируя их, вы заставите вашу программу работать намного быстрее.

На самом деле в вашем коде может быть сделано еще несколько улучшений, но это тема другого дня. Исправление алгоритмической сложности принесет ее в неразрывную сферу вещей.

0

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector