[英]8 Tile Puzzle via BFS
I have searched the depths of the internet and I am yet to find a solution to my problem. 我已经搜索了互联网的深度,但尚未找到解决问题的方法。 I have implemented(I think) a BFS for the sliding tile game. 我已经为滑动图块游戏实现了BFS。 However, It cannot solve a problem unless the state is a few steps away otherwise it just results in Out of Memory errors. 但是,除非状态距离只有几步之遥,否则它无法解决问题,否则只会导致内存不足错误。 So my question to you, where am I going wrong? 所以我问你,我要去哪里错了? AFAIK my code follows the BFS pseudo code. AFAIK我的代码遵循BFS伪代码。
EDIT/NOTE: I have stepped through with a debugger and have yet to find anything out of the ordinary to my eye but I am merely a novice programmer comparatively. 编辑/注意:我已经调试过调试器,但还没有发现任何与众不同的东西,但是相对而言,我只是一个新手程序员。
#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
There are a number of inneficiencies in your code that are slowing it down. 您的代码中有许多不足之处正在减慢它的速度。 I'm actually surprised you had the patience to wait for it to reach an out-of-memory condition. 实际上,我很惊讶您有耐心等待它达到内存不足的状态。
The main culprits are the searches: std::find(visitedList.begin(), visitedList.end(), child) != visitedList.end() //and std::find(nodesToVisit.begin(), nodesToVisit.end(), child) == nodesToVisit.end()
主要的罪魁祸首是搜索: std::find(visitedList.begin(), visitedList.end(), child) != visitedList.end() //and std::find(nodesToVisit.begin(), nodesToVisit.end(), child) == nodesToVisit.end()
Both of these execute in O(N), which sounds fine, but since you execute them on every node, that results in a O(N 2 ). 两者都在O(N)中执行,这听起来不错,但是由于您在每个节点上都执行它们,因此结果为O(N 2 )。
You can fix this by using a std::unordered_set<>
for the visitedList
. 您可以通过对visitedList
使用std::unordered_set<>
来解决此visitedList
。 Also, you could add nodes to the visited_list
as soon as you queue them (instead of when you dequeue them). 同样,您可以在将节点排队时(而不是在将它们出队时)将其添加到visited_list
列表中。 This way, you would only have a single lookup to do. 这样,您只需进行一次查找。
NB You will have to specialize std::hash<State>
in order to use std::unordered_set
. 注意:您必须专门使用std::hash<State>
才能使用std::unordered_set
。
One more hint: these cout << ...
in your main loop really slow you down because they force a flush and sync with the OS by default, commenting these out will make your program run a lot faster. 还有一个提示:在主循环中的这些cout << ...
确实会减慢您的速度,因为它们默认情况下会强制刷新并与OS同步,注释掉这些注释将使您的程序运行更快。
There's actually quite a few more improvements that could be made in your code, but that's a topic for another day. 实际上,您的代码中还可以进行很多改进,但这是另一天的话题。 Fixing the algorithmic complexity will bring it in the non-broken realm of things. 修复算法复杂性会将其带入事物的不间断领域。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.