0

我正在为一个学校项目创建一个游戏,我想使用 Dijkstra 的算法作为 AI 的一部分,用于玩家需要躲避的物体。

所以我有一个图(邻接矩阵),我想使用 Dijkstra 来获取从每个对象到玩家的路径,但是现在当我调用算法时,如果玩家跟随对象,它将找不到玩家。

据我了解,Dijkstra 的算法应该访问所有节点,直到找到目的地,但在我的情况下不是。

这是我的算法到目前为止的样子:

Node* Graph::DijkstrasAlgorithm(Node* sNode, Node* dNode){
    std::cout<<"Hello Dijkstra!!"<<std::endl;
    for(unsigned int i = 0; i < this->nodeList.size(); ++i){
        nodeList.at(i)->setDistance(INT_MAX);
        nodeList.at(i)->setVisited(false);
    }
    std::cout<<"everything is set"<<std::endl;
    sNode->setDistance(0);
    int numberVisited = 0;
    Node* u = new Node();
    std::cout<<"before while lus"<<std::endl;
    while(numberVisited < numberOfNodes){
        u->setDistance(INT_MAX);
        for(unsigned int j = 0; j < this->nodeList.size(); ++j){
            if((u->getDistance() > this->nodeList.at(j)->getDistance()) && !this->nodeList.at(j)->isVisited() ){
                u = this->nodeList.at(j);
                u->setVisited(true);
                numberVisited++;
            }
        }

    std::cout<<u->getNodeName()<<"=="<<dNode->getNodeName()<<std::endl;
        if((u == dNode) || (u->getDistance() == INT_MAX)){
            std::cout<<"true"<<std::endl;
            break;
        }


        for(int k = 0; k < u->numberOfneighbors(); ++k){
            if(!u->getNeighbors(k)->isVisited())
            {
            //  std::cout<<u->getDistance()<<std::endl;
                int alt = u->getDistance() + 1;
                if( alt < u->getNeighbors(k)->getDistance()){
                     u->getNeighbors(k)->setDistance(alt);
                     u->getNeighbors(k)->setPrevious(u);
                }
            }
        }

    }
    std::vector<Node* > stack;
    u = dNode;
    while(u->getPrevious() != NULL){
        stack.insert(stack.begin(), u);
        u = u->getPrevious();
    }
    if(!stack.empty())
        return stack.at(0);
    else
        return sNode;


}

在这种情况下,dNode是目的节点,sNode是起始节点。

有谁知道我做错了什么?

4

2 回答 2

3

在 Dijkstra 算法中,您仅将最短增广路径指向的节点标记为已访问。我可以看到你在这里犯的一个错误:

u = this->nodeList.at(j);
u->setVisited(true);

不要立即将节点标记为已访问。

仅标记为已访问的节点u将在循环后指向

for(unsigned int j = 0; j < this->nodeList.size(); ++j){

否则,对于每一项改进,您都会将节点标记为已访问,甚至不会处理所有节点。

于 2013-01-03T09:29:00.103 回答
1

它甚至不像 Dijkstra 算法。

要实现 Dijkstra 算法,您需要维护两个节点列表:

  • 搜索到的节点列表
  • 边缘节点的排序列表。
    此列表中的每个节点都有到达此位置的成本。

我在您的代码中都没有看到这些列表。

您还将成本存储在节点中。这将不起作用,因为到达节点的成本将取决于路线(除非您可以存储与节点关联的多个成本)。

我希望代码看起来像这样:

 // pseudo code.
 // Note all features used are strictly available
 //
 Node* Graph::DijkstrasAlgorithm(Node* sNode, Node* dNode)
 {
     std::list<Node*>                    searchedNodes;
     std::list<std::pair<Node*, cost>>   edgeNodes;

     edgeNodes.push_sorted(sNode, 0);

     while(!edgeNodes.empty())
     {
          std::pair<Node*, cost>  next = edgeNodes.pop_front();
          searchedNodes.push_back(next.first);

          if (next.first == dnode)
          {   // We found the route
              return STUFF;
          }

          for(Edge* edge, next.first->getEdges())
          {
              if (searchedNodes.find(edge->dst) != searchedNodes.end())
              {   continue;
              }

              edgeNodes.push_sorted(dest.dst, next.second + edge->cost);
          }
     }
 }
于 2013-01-03T09:44:24.397 回答