4

配列 [15*15] とパスを取り、パスを埋めるときに実行したステップのキューを生成するフラッド フィル アルゴリズムを実装しました。tl;dr それはこのように見えます

std::queue <int> f_path;

void Enemy::find_path(int *map, int *grid, int node) {

    if (grid[node] == 1) // colored-grid
        return;
    if (map[node] == 0) // grid with defined map (0 - no path, 1 path)
        return;

    f_path.push(node);
    grid[node] = 1;

    if ((node + 1) % 15 != 0) this->find_path(map, grid, node + 1); // go right
    if (node % 15 != 0) this->find_path(map, grid, node - 1); // go left
    if (node - 15 > 0) this->find_path(map, grid, node - 15); // go up
    if (node + 15 < 15*15) this->find_path(map, grid, node + 15); // go down
}

しかし、グリッドを埋めるために必要なステップのキューができましたが、オブジェクトが最初から最後までたどり、取得するためにこの情報を適用する方法がわかりません。つまり、1 つのパスで単純ですが、次のように分割された場合 (9 は出口):
0 0 1 0 0
0 1 1 1 0
0 1 0 1 0
0 1 1 1 0
0 0 9 0 0
両方があります。キュー内の左右のパスなので、単純な go(f_path.front()) を実行すると、神が何を知っているかがわかります。どうすればそれをフィルタリングして、終了してから停止するだけですか? 頭を包むことはできません。

4

3 に答える 3

3

アルゴリズムの正確な内部構造はわかりませんが、現在のパス要求で見つかった開始ノードからの最小距離をすべてのノードに関連付けることで、目的地までの最短パスを簡単に取得できます。

このようにして、距離が保存されたものよりも小さい場合に同じセルから通過する別のパスを見つけるたびに、このパスは以前のものよりも優れています。そうでない場合は、無視して次のパスにスキップできます。

このようにして、ゴールに到達する複数のパスを持つことになりますが、それらはすべて同じ長さになります (したがって、そのうちの 1 つを選択することができます)。ゴール ノードに到達したら、バックトラックできます。ゴールから始まる距離xにあるすべてのノードについて、距離x-1にあるネイバーを検索します。

私が何を意味するかをグラフィカルに説明するために:

ここに画像の説明を入力

これは最速のソリューションではなく、小さなタイル マップにのみ適していることに注意してください。大きなタイル マップでは、幅優先検索よりも優れたアルゴリズムが必要になります。

于 2013-01-12T22:08:58.757 に答える
2

Deith、あなたは正しい道を進んでいると断言します!

現時点では、コードは単純にすべてを反復処理し、どこにも到達しません。あなたはいくつかのことを忘れました。
まず、Enemy::find_path宛先に到達したかどうかに関係なく、ブール値を返す必要があります。だから、あなたが持っている上部に

if (grid[node] == 1) // colored-grid
    return;
if (map[node] == 0) // grid with defined map (0 - no path, 1 path)
    return;

最初のものは、それ自体が後戻りしないようにすることであることに気付きました。
2 つ目は非常に明確です。壁にぶつかります。return falseただし、目的地に到達した場合に true を返すように、3 分の 1 が必要です。

次に、4 方向の反復を呼び出したときに、 が返されるかどうかをテストしtrueます。目標が達成されてからもう一度実行するreturn trueと、検索、検出、およびソースへの圧縮が行われます。

それはあなたが使用できる部分だからです。現在、あなたのキューはどこにでも行くランダムなジャンクでいっぱいになります. 間違った方向に進んだ後、空になりません。ただし、zip-back 部分は完璧です。キューの代わりにスタックを使用し、宛先に到達したら、zip でスタックに戻るときに各ノードをプッシュすることで、最初から最後までの完全なパスを提供します!

私が助けてくれることを願っています;-)

編集: わかりました。もう 1 つ重要な点があります。機能しているが非効率的なパスです。
アルゴリズムパスを見つけますが、常に最短のパスを見つけるとは限りません。実際、非常に長いパスを見つけることさえあります。幸いなことに、これを修正するのはやや簡単です。まず、目的地の座標が必要です。次に、関数の反復ごとに、方向反復子を並べ替えます。最初に右、次に左、次に上、次に下を選択します。代わりに、どちらの方向がゴールの方向に向かうかを確認してください。次に、その方向を確認します。失敗した場合は、次に近いものを試してください。それが失敗した場合は、次に近いものを試してから、次に近いものを試してください (まあ、今は一番遠いです)。はい、私はこれがそうではないことを知っていますfind_path

短距離は、一般的に壁にぴったり合う傾向があるためですが、完全にランダムな方向に進むよりは間違いなく優れています.

于 2013-01-12T22:25:25.150 に答える
0

取得した最終グリッドで深さ優先検索 (dfs) を実行します。

http://en.wikipedia.org/wiki/Depth-first_search

個々のパスを取得します。最短のものを選択したい場合、実行できる最適化はほとんどありません。

  • dfs がそれよりも先に見える場合は、そのパスをスキップします。
  • 最大制限よりも短い長さのパスが見つかった場合。max-limit をそれに設定します。

これが役立つことを願っています。

編集:私はこのコードを書きました。それはあなたのために働くはずです。x、y座標としてのベクトル<ペア>で、最短パスを提供します。

#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>

using namespace std;

ifstream fin("map.txt");

int width, height;
int map[10][10];
// Start (x,y), End (x,y)
int sy, sx, ey, ex;

bool visited[10][10];

vector<pair<int, int> > final_path;
int max_size = 9999;

void getInput() {
  fin >> width >>  height;

  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
        int x;
        fin >> x;
        map[i][j] = x; 

        if(x == 8){
          sy = i;
          sx = j;
        }

        if(x == 9){
          ey = i;
          ex = j;
        }
    }
  }
}

void dfs(int x, int y, vector<pair<int, int> > path) {
  if(path.size() > max_size){
    cout << "Returning : path size too big" << endl;
    return;
  }

  if(x < 0 || x >= width || y < 0 || y >= height){
    cout << "Returning : bounds" << endl;
    return;
  }

  // If the tile is blocked, can't go there
  if(map[y][x] == 0){
    cout << "Returning : blocked" << endl;
    return;
  }

  if(visited[y][x]){
    cout << "Returning : visited" << endl;
    return;
  }

  // We don't want to revisit a tile
  visited[y][x] = true;

  cout << "Visiting " << x << " " << y << endl;

  path.push_back(make_pair(x, y));
  if(map[y][x] == 9) {
    final_path = path;
    visited[y][x] = false;
    return;
  }

  dfs(x, y - 1, path);
  dfs(x + 1, y, path);
  dfs(x, y + 1, path);
  dfs(x - 1, y, path);

  visited[y][x] = false;

  return;
}

int main() {

  getInput();
  cout << "Got Input" << endl;
  cout << width << " " << height << endl;

  memset(visited, 0, sizeof(visited));
  vector<pair<int, int> > starting_path;

  cout << sx << " " << sy << endl;

  dfs(sx, sy, starting_path);

  cout << "Path size is " << final_path.size() << endl;

  for(int i = 0; i < final_path.size(); i++){
    cout << final_path[i].first << " " << final_path[i].second << endl;
  }

  return 0;
}

map.txt には、質問で指定したマップが含まれています。

于 2013-01-12T22:26:18.307 に答える