A* and N-Puzzle optimization
A* and N-Puzzle optimization
我正在为N-Puzzle编写一个求解器(请参阅http://en.wikipedia.org/wiki/Fifteen_puzzle)
现在我正在使用一个无序映射来存储拼图板的哈希值,并以曼哈顿距离作为算法的启发式算法,这是一个简单的DFS。
所以我有
auto pred = [](Node * lhs, Node * rhs){ return lhs->manhattanCost_ < rhs->manhattanCost_; };
std::multiset<Node *, decltype(pred)> frontier(pred);
std::vector<Node *> explored; // holds nodes we have already explored
std::tr1::unordered_set<unsigned> frontierHashTable;
std::tr1::unordered_set<unsigned> exploredHashTable;
这对于n=2和3非常有效。然而,对于n=4及以上的情况,它确实是命中率很高。(stl无法为新节点分配内存)
我还怀疑我在无序集中遇到了哈希冲突
unsigned makeHash(const Node & pNode)
{
unsigned int b = 378551;
unsigned int a = 63689;
unsigned int hash = 0;
for(std::size_t i = 0; i < pNode.data_.size(); i++)
{
hash = hash * a + pNode.data_[i];
a = a * b;
}
return hash;
}
16!=2×10^13(可能的安排)
2^32=4 x 10^9(32位散列中可能的散列值)
我的问题是如何优化我的代码以解决n=4和n=5的问题?我从这里知道http://kociemba.org/fifteen/fifteensolver.html
http://www.ic-net.or.jp/home/takaken/e/15pz/index.html
平均在不到一秒钟的时间内n=4是可能的。
编辑:算法本身就在这里:
bool NPuzzle::aStarSearch()
{
auto pred = [](Node * lhs, Node * rhs){ return lhs->manhattanCost_ < rhs->manhattanCost_; };
std::multiset<Node *, decltype(pred)> frontier(pred);
std::vector<Node *> explored; // holds nodes we have already explored
std::tr1::unordered_set<unsigned> frontierHashTable;
std::tr1::unordered_set<unsigned> exploredHashTable;
// if we are in the solved position in the first place, return true
if(initial_ == target_)
{
current_ = initial_;
return true;
}
frontier.insert(new Node(initial_)); // we are going to delete everything from the frontier later..
for(;;)
{
if(frontier.empty())
{
std::cout << "depth first search " << "cant solve!" << std::endl;
return false;
}
// remove a node from the frontier, and place it into the explored set
Node * pLeaf = *frontier.begin();
frontier.erase(frontier.begin());
explored.push_back(pLeaf);
// do the same for the hash table
unsigned hashValue = makeHash(*pLeaf);
frontierHashTable.erase(hashValue);
exploredHashTable.insert(hashValue);
std::vector<Node *> children = pLeaf->genChildren();
for( auto it = children.begin(); it != children.end(); ++it)
{
unsigned childHash = makeHash(**it);
if(inFrontierOrExplored(frontierHashTable, exploredHashTable, childHash))
{
delete *it;
}
else
{
if(**it == target_)
{
explored.push_back(*it);
current_ = **it;
// delete everything else in children
for( auto it2 = ++it; it2 != children.end(); ++it2)
delete * it2;
// delete everything in the frontier
for( auto it = frontier.begin(); it != frontier.end(); ++it)
delete *it;
// delete everything in explored
explored_.swap(explored);
for( auto it = explored.begin(); it != explored.end(); ++it)
delete *it;
return true;
}
else
{
frontier.insert(*it);
frontierHashTable.insert(childHash);
}
}
}
}
}
由于这是家庭作业,我将建议您尝试一些策略。
首先,尝试使用valgrind或类似工具检查内存泄漏。如果你不删除所有新的内容,你可能会有一些内存泄漏。
其次,计算应该探索的节点数量的界限。跟踪您所探索的节点的数量。如果您通过了界限,则可能无法正确检测循环。
第三,尝试深度优先搜索的算法,而不是A*。它的内存需求在树的深度上应该是线性的,它应该只是改变排序(pred)的问题。如果DFS有效,您的A*搜索可能探索了太多节点,或者您的内存结构可能效率太低。如果DFS不起作用,则可能再次出现循环问题。
第四,尝试更紧凑的内存结构。例如,std::multiset可以执行您想要的操作,但带有std::deque的std::priority_queue可能占用较少的内存。你还可以尝试其他的改变,看看它们是否能改善情况。
首先我建议使用cantor扩展,它可以用作哈希方法。这是1比1,即16!可能的安排将被散列成0~16!-1。
然后我会自己实现map
,正如你可能知道的,std
对于计算来说不够有效。map
实际上是Binary Search Tree
,我建议使用Size Balanced Tree
,或者您可以使用AVL tree
。
为了记录,直接使用bool hash[]
&CCD_ 8也可以获得良好的结果。
然后是最重要的-A* function
,就像你链接的第一个一样,你可以尝试各种A* function
,找到最好的。
您只使用启发式函数对多集进行排序。您应该使用min(g(n) + f(n))
,即最小值(路径长度+启发式)来排序您的边界。
问题是,你选择的是启发式最少的一个,这可能不是正确的"下一个孩子"。
我相信这就是导致你的计算爆炸的原因。
- OpenACC CPU vs GPU optimization
- "Empty base optimization" lambda 捕获 - 标准禁止?为什么?
- OpenGL ES glTexImage2D optimization
- CPLEX ILOG OPL Optimization
- uninitialized_copy memcpy/memmove optimization
- 减小 Wasm 文件大小(libc、optimization、emscripten)
- drawScanlineWithDepth - optimization
- OpenGL Optimization
- c++, levmar optimization, lapack, tnt library
- G++:移动到另一个翻译单元会中断"const optimization"?
- 为什么这"optimization"减慢我的程序?
- JNI "Optimization"值得吗?
- Compiler Optimization with return (std::stringstream ss).str
- A* and N-Puzzle optimization
- 为什么 g++ 使我的代码以与编写不同的顺序执行,我如何禁用此"optimization"?
- C++11 for_each and lambdas optimization
- 在Opencv - Optimization中加载YML文件
- OpenGL Optimization or...?