- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
情况:我正在尝试将 A* 算法转换为不允许对角线移动的 C++ 代码,但我有一些奇怪的行为。
我的问题:即使没有可能的对角线移动,是否也需要考虑对角线成本。当我在没有对角线成本的情况下进行计算时(“启发式”因子为 10),我的 fscore 总是相同的 80(你可以在我计算 fscore、gscore 和 hscore 的第二张图片中看到这一点)这看起来真的很奇怪我。因此(几乎所有节点的 fscore 都为 80)该算法似乎不起作用,因为许多节点具有相同的最小 fscore 80。
或者这是正常行为,没有对角线的 A* 星实现是否必须执行更多工作(因为更多节点具有相同的最小 fscore)?
我不认为这个问题与我的代码有任何关系,而不是与我的推理有关,但我还是发布了它:
路径查找.cpp
#include "pathFind.h"
#include <queue>
#include "node.h"
#include <QString>
#include <QDebug>
#include <iostream>
/** Pathfinding (A* algo) using Manhatten heuristics and assuming a monotonic, consistent
* heuristic (the enemies do not change position)
*
* TODO: add variable terrain cost
**/
//dimensions
const int horizontalSize = 20;
const int verticalSize = 20;
//nodes sets
static int closedNodes[horizontalSize][verticalSize]; //the set of nodes already evaluated
static int openNodes[horizontalSize][verticalSize]; // the set of nodes to be evaluated; initialy only containing start node
static int dir_map[horizontalSize][verticalSize]; //map of directions (contains parents-children connection)
//directions
const int dir=4;
static int dirX[dir]={1,0,-1,0};
static int dirY[dir]={0,1,0,-1};
//test class
static int map[horizontalSize][verticalSize]; //map of navigated nodes
pathFind::pathFind(){
//test
srand(time(NULL));
//create empty map
for (int y=0;y<verticalSize;y++){
for (int x=0;x<horizontalSize;x++){
map[x][y]=0;
}
}
//fillout matrix
for (int x=horizontalSize/8;x<horizontalSize*7/8;x++){
map[x][verticalSize/2]=1;
}
for (int y=verticalSize/8;y<verticalSize*7/8;y++){
map[horizontalSize/2][y]=1;
}
//randomly select start and finish locations
int xA,yA,xB,yB;
int n=horizontalSize;
int m=verticalSize;
xA=6;
yA=5;
xB = 14;
yB = 12;
qDebug() <<"Map Size (X,Y): "<<n<<","<<m<<endl;
qDebug()<<"Start: "<<xA<<","<<yA<<endl;
qDebug()<<"Finish: "<<xB<<","<<yB<<endl;
// get the route
clock_t start = clock();
QString route=calculatePath(xA, yA, xB, yB);
if(route=="") qDebug() <<"An empty route generated!"<<endl;
clock_t end = clock();
double time_elapsed = double(end - start);
qDebug()<<"Time to calculate the route (ms): "<<time_elapsed<<endl;
qDebug()<<"Route:"<<endl;
qDebug()<<route<<endl<<endl;
}
QString pathFind::calculatePath(const int & xStart, const int & yStart,const int & xFinish, const int & yFinish){
/** why do we maintain a priority queue?
* it's for maintaining the open list: everytime we acces the open list we need to find the node with the lowest
* fscore. A priority queue is a sorted list so we simply have to grab (pop) the first item of the list everytime
* we need a lower fscore.
*
* A priority queue is a data structure in which only the largest element can be retrieved (popped).
* It's problem is that finding an node in the queue is a slow operation.
**/
std::priority_queue<node> pq[2]; //we define 2 priority list which is needed for our priority change of a node 'algo'
static int index; //static and global variables are initialized to 0
static node *currentNode;
static node *neighborNode;
//first reset maps
resetMaps();
//create start node
static node * startNode;
startNode= new node(xStart,yStart,0,0);
startNode->updatePriority(xFinish, yFinish);
// push it into the priority queue
pq[index].push(*startNode);
//add it to the list of open nodes
openNodes[0][0] = startNode->getPriority();
//A* search
//while priority queue is not empty; continue
while(!pq[index].empty()){
//get current node with the higest priority from the priority list
//in first instance this is the start node
currentNode = new node(pq[index].top().getxPos(),
pq[index].top().getyPos(),
pq[index].top().getDistance(),
pq[index].top().getPriority());
//remove node from priority queue
pq[index].pop();
openNodes[currentNode->getxPos()][currentNode->getyPos()]=0; //remove node from open list
closedNodes[currentNode->getxPos()][currentNode->getyPos()]=1; //add current to closed list
//if current node = goal => finished => retrace route back using parents nodes
if (currentNode->getxPos()==xFinish && currentNode->getyPos()==yFinish){
//quit searching if goal is reached
//return generated path from finish to start
QString path="";
int x,y,direction; //in cpp you don't need to declare variables at the top compared to c
//currentNode is now the goalNode
x=currentNode->getxPos();
y=currentNode->getyPos();
while (!(x==xStart && y==yStart)){
/** We start at goal and work backwards moving from node to parent
* which will take us to the starting node
**/
direction=dir_map[x][y];
path =(direction+dir/2)%dir+path; //we work our way back
//iterate trough our dir_map using our defined directions
x+=dirX[direction];
y+=dirY[direction];
}
//garbage collection; the memory allocated with 'new' should be freed to avoid memory leaks
delete currentNode;
while (!pq[index].empty()){
pq[index].pop();
}
return path;
//return path;
} else {
//add all possible neighbors to the openlist + define parents for later tracing back
//(four directions (int dir): up, down, left & right); but we want to make it
//as extendable as possible
for (int i=0; i<dir; i++){
//define new x & y coord for neighbor
//we do this because we want to preform some checks before making this neighbore node
int neighborX = currentNode->getxPos()+dirX[i];
int neighborY = currentNode->getyPos()+dirY[i];
//check boundaries
//ignore if on closed list (was already evaluted) or if unwalkable (currently not implemented)
if (!(neighborX <0 || neighborY <0 || neighborX > horizontalSize || neighborY > verticalSize ||
closedNodes[neighborX][neighborY]==1)){
//ok -> generate neighbor node
neighborNode = new node (neighborX,neighborY,currentNode->getDistance(),currentNode->getPriority());
//calculate the fscore of the node
neighborNode->updatePriority(xFinish,yFinish);
neighborNode->updateDistance();
//if neighbor not in openset => add it
if(openNodes[neighborX][neighborY]==0){
//add it to open set
openNodes[neighborX][neighborY]=neighborNode->getPriority();
//add it to the priority queue (by dereferencing our neighborNode object
//pq is of type node; push inserts a new element;
//the content is initialized as a copy
pq[index].push(*neighborNode);
//set the parent to the node we are currently looking at
dir_map[neighborX][neighborY]=(i+dir/2)%dir;
//if neighbor is already on open set
//check if path to that node is a better one (=lower gscore) if we use the current node to get there
} else if(openNodes[neighborX][neighborY]>neighborNode->getPriority()) {
/** lower gscore: change parent of the neighbore node to the select square
* recalculate fscore
* the value of the fscore should also be changed inside the node which resides inside our priority queue
* however as mentioned before this is a very slow operation (is going to be the bottleneck of this implemention probably)
* we will have to manuall scan for the right node and than change it.
*
* this check is very much needed, but the number of times this if condition is true is limited
**/
//update fscore inside the open list
openNodes[neighborX][neighborY]=neighborNode->getPriority();
//update the parent node
dir_map[neighborX][neighborY]=(i+dir/2)%dir;
//we copy the nodes from one queue to the other
//except the -old-current node will be ignored
while (!((pq[index].top().getxPos()==neighborX) && (pq[index].top().getyPos()==neighborY))){
pq[1-index].push(pq[index].top());
pq[index].pop();
}
pq[index].pop(); //remove the -old-current node
/** ?? **/
if(pq[index].size()>pq[1-index].size()){ //??? is this extra check necessary?
index=1-index; //index switch 1->0 or 0->1
}
while(!pq[index].empty()){
pq[1-index].push(pq[index].top());
pq[index].pop();
}
/** ?? **/
index=1-index; //index switch 1->0 or 0->1
pq[index].push(*neighborNode); //and the -new-current node will be pushed in instead
} else delete neighborNode;
}
}
delete currentNode;
}
} return ""; //no path found
}
void pathFind::resetMaps(){
for (int y=0;y<horizontalSize;y++){
for (int x=0;x<verticalSize;x++){
closedNodes[x][y]=0;
openNodes[x][y]=0;
}
}
}
节点.cpp
#include "node.h"
#include <stdio.h>
#include <stdlib.h>
/** constructor **/
node::node(int x,int y, int d,int p)
{
xPos=x;
yPos=y;
distance=d;
priority=p;
}
/** getters for variables **/
//current node xPosition
int node::getxPos() const {
return xPos;
}
//current node yPosition
int node::getyPos() const {
return yPos;
}
//gscore
int node::getDistance() const {
return distance;
}
//fscore
int node::getPriority() const {
return priority;
}
/** Updates the priority; the lower the fscore the higer the priority
* the fscore is the sum of:
* -path-cost (gscore) (which is the distance from the starting node to the current node)
* -heuristic estimate (hscore) (which is an estimate of the distance from the current node to the destination node)
*
**/
void node::updatePriority(const int & xDest, const int & yDest){
priority = distance + estimateDistance(xDest,yDest)*10;
}
void node::updateDistance(){//const int & direction
distance +=10;
}
/** Estimate function for the remaining distance to the goal
* here it's based on the Manhattan distance;
* which is the distance between two points in a grid based on a strictly horizontal & veritcal path;
* => sum of vertical & horizontal components
**/
const int & node::estimateDistance(const int & xDest, const int & yDest) const{
static int xDistance,yDistance,totalDistance;
xDistance=xDest-xPos;
yDistance=yDest-yPos;
totalDistance=abs(xDistance)+abs(yDistance);
return (totalDistance);
}
/** class functor (I think) to compare elements using:
* operator overloading: "<" gets overloaded which we are going to use in our priority queue
* to determine priority of a node in our queue;
* returns true if node a has a lower fscore compared to node b
*
* there is an ambiguity here: < -- >; better to make both >
* also prototype is now friend which could probably be replaced with this for the first
* argument; it advantage is that because of the friend function the operand order can be reversed
* this doesn't really looks to favor our application; so should I use it or not?
**/
bool operator<(const node & a, const node & b){
return a.getPriority() > b.getPriority();
}
最佳答案
我认为你的算法没有问题,如果没有对角线移动,就没有必要考虑了。曼哈顿距离是一种简单的启发式方法,当您离目标节点越近时,H 函数给出的数字越小,尽管 G 函数(从第一个节点到此处的距离)变大。结果,许多节点具有相同的 f 分数。
关于c++ - 无对角线移动的星型算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14162925/
只是想知道 Jquery Mobile 是否足够稳定以用于实时生产企业移动应用程序。 有很多 HTML5 框架,因为我们的团队使用 JQuery 已经有一段时间了,我们更愿意使用 Jquery 移动框
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 3 年前。 Improve t
所以我尝试在 JavaScript 中对元素进行拖放。我使用的视频教程在这里; https://www.youtube.com/watch?v=KTlZ4Hs5h80 。我已经按照它的说明进行了编码,
无法在移动 iOS(safari 和 chrome)上自动播放以前缓存的 mp3 音频 我正在 Angular 8 中开发一个应用程序,在该应用程序的一部分中,我试图在对象数组中缓存几个传入的音频 m
Git 基于内容而不是文件,所以我目前理解以下行为,但我想知道是否有特殊选项或 hack 来检测此类事情: git init mkdir -p foo/bar echo "test" foo/a.tx
我正在寻找语义 ui 正确的类来隐藏例如移动 View 中的 DIV。在 Bootstrap 中,我们有“visible-xs”和“hidden-xs”。 但是在语义ui上我只找到了“仅移动网格” 最
我正在使用 ubuntu 和 想要移动或复制大文件。 但是当我与其他人一起使用服务器时,我不想拥有所有内存并使其他进程几乎停止。 那么有没有办法在内存使用受限的情况下移动或复制文件? 最佳答案 如果你
这些指令有什么区别?以 ARM9 处理器为例,它不应该是: ASM: mov r0, 0 C: r0 = 0; ASM: ld r0, 0 C: r0 = 0; ? 我不知道为什么要使用一个或另一个:
我有一个文件夹,其中包含一些随机命名的文件,其中包含我需要的数据。 为了使用数据,我必须将文件移动到另一个文件夹并将文件命名为“file1.xml” 每次移动和重命名文件时,它都会替换目标文件夹中以前
我经常在 IB/Storyboard 中堆叠对象,几乎不可能拖动其他对象后面的对象而不移动前面的对象。无论如何我可以移动已经选择但位于其他对象后面的对象吗?当我尝试移动它时,它总是选择顶部的对象,还是
几个月前,我看到 Safari 7 允许推送通知,它似乎是一个非常有用的工具,除了我看到的每个示例都专注于桌面浏览,而不是移动设备。 Safari 推送通知是否可以在移动设备上运行,如果没有,是否有计
我有一个简单的 View 模型,其中包含修改后的 ObservableCollection使用 SynchronizationContext.Current.Send在 UI 线程上执行对集合的更改。
关于cassandra创建的数据文件和系统文件的位置,我需要移动在“cassandra.yaml”配置文件中设置的“commitlog_directory”、“data_file_directorie
我有这个代码 $(function() { var message = 'Dont forget us'; var original; var txt1 = ' - '; $(wind
我的客户报告说他的网站有一个奇怪的问题。该网站的 URL 是 your-montenegro.me 在 基于 Android 的浏览器 上加载时,页面底部会出现一个奇怪的空白区域。以下是屏幕截图: 华
我有这个 HTML 标记: Express 300 bsf Sign Up 我需要将元素从 DOM 上的一个
我有一个可重新排序的 TableView (UITableView 实例)。尽管我已经实现了 UITableViewDataSource 方法: tableView:moveRowAtIndexPat
我的客户报告说他的网站有一个奇怪的问题。该网站的 URL 是 your-montenegro.me 在 基于 Android 的浏览器 上加载时,页面底部会出现一个奇怪的空白区域。以下是屏幕截图: 华
我需要在拖放或复制/剪切和粘贴(复制与移动)期间获取操作类型。它是一个 Swing 应用程序,并且实现了 TransferHandle。我在操作结束时需要此信息,在 importData 方法中。 对
我编写了一个具有 add 和 get 方法的 SortedIntList 类。 我调用以下四个方法: SortedIntList mySortedIntList = new SortedIntList
我是一名优秀的程序员,十分优秀!