<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      一種單目標(biāo)A*算法設(shè)計(jì)與實(shí)現(xiàn)

      一種單目標(biāo)A*算法設(shè)計(jì)與實(shí)現(xiàn)

      作者:吳屏珊

      • 最近在學(xué)習(xí)簡(jiǎn)單的單目標(biāo)A*算法,其中在CSDN上閱讀到的一篇博文給了我很大啟發(fā),于是在該博文的基礎(chǔ)上,筆者記錄了一點(diǎn)自己對(duì)于A*算法的體會(huì)和感悟。
      • 原文鏈接

      目錄



      1. A*算法簡(jiǎn)單介紹

      1.1 A*算法的基本要素

      Image
      1、圖的說明:有一個(gè)8*8的地圖,其中綠色的點(diǎn)為起點(diǎn),紅色的點(diǎn)為終點(diǎn),黑色的點(diǎn)為障礙點(diǎn)(即不可達(dá)點(diǎn)),當(dāng)然邊界也是不可達(dá)點(diǎn)。

      2、將要實(shí)現(xiàn)的目標(biāo):從起點(diǎn)走到終點(diǎn),其中要求所走距離最短并且要繞開所有不可達(dá)點(diǎn)。
      3、移動(dòng)方向:每個(gè)點(diǎn)只有上,下,左,右四個(gè)方向可以行進(jìn)。

      1.2 A*算法的中心思想

      • 我們首先思考一個(gè)問題作為引入:既然每一個(gè)點(diǎn)有四種移動(dòng)方向,那如何判斷該點(diǎn)下一步的移動(dòng)方向呢,如何選出在該點(diǎn)下一步即將到達(dá)的所有點(diǎn)中選出最好的點(diǎn)呢?
        (1)這里我們需要用到一個(gè)公式:F=G+H;其中F稱為代價(jià),G為從起點(diǎn)到該點(diǎn)已走過的距離,H為從該點(diǎn)到終點(diǎn)將走的曼哈頓距離。
        (2)曼哈頓距離:在地圖上我們忽略所有障礙點(diǎn)(不可達(dá)點(diǎn)),兩點(diǎn)的橫坐標(biāo)之差的絕對(duì)值與縱坐標(biāo)之差的絕對(duì)值之和即為兩點(diǎn)之間的曼哈頓距離,數(shù)學(xué)公式表示如下:\({|x_1-x_2|+|y_1-y_2|}\) ;代碼表示如下:Math.abs(x1-x2)+Math.abs(y1-y2)
        (3)選取移動(dòng)方向的依據(jù):F,每次移動(dòng)前,計(jì)算下一步可到達(dá)點(diǎn)的 F 值,然后對(duì)所有可到達(dá)點(diǎn)(不限于下一步)的 F 值進(jìn)行比較,優(yōu)先選取移動(dòng)代價(jià)最小即 F 值最小的點(diǎn)。

      1.3 A*算法所需數(shù)據(jù)結(jié)構(gòu)

      1.3.1 定義點(diǎn)Node的結(jié)構(gòu)

      1、點(diǎn)的坐標(biāo)(x,y)
      2、計(jì)算點(diǎn)的代價(jià)時(shí)所需數(shù)值:F,G,H
      3、父節(jié)點(diǎn):Father;父節(jié)點(diǎn)記錄的是該節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)(即該節(jié)點(diǎn)是由哪個(gè)節(jié)點(diǎn)遍歷到的)。
      ? 父節(jié)點(diǎn)的作用:A*算法從起點(diǎn)開始尋路,當(dāng)找到終點(diǎn)的時(shí)候代表最短路徑已經(jīng)找到,這時(shí)我們可以利用終點(diǎn)結(jié)構(gòu)的Father來回溯到起點(diǎn)(起點(diǎn)的Father為NULL),從而找出并且輸出這條最短路徑。

      1.3.2 記錄點(diǎn)狀態(tài)的幾個(gè)表

      1、優(yōu)先隊(duì)列Open表:記錄由該點(diǎn)下一步可以到達(dá)的所有點(diǎn),并且每次將F值最小的點(diǎn)放在隊(duì)首。
      2、Close表:記錄所有已經(jīng)走過的點(diǎn)。
      3、Exist表:記錄所有遍歷過的點(diǎn)(即在Open與Close中出現(xiàn)過的點(diǎn))。
      4、Close表與Exist表的區(qū)別:Close中存儲(chǔ)的點(diǎn)是已走過的點(diǎn),Exist表中存儲(chǔ)的點(diǎn)是已遍歷過,但不一定走過的點(diǎn)。

      2. A*算法步驟演示

      • Open表不為空且未找到終點(diǎn)時(shí)一直進(jìn)行循環(huán)

      2.1 第一輪操作

      • 首先我們將起點(diǎn)放入Open表中

        alt textalt text
      • 在Open表中找到當(dāng)前F值最小的結(jié)點(diǎn)A,并將該點(diǎn)移出Open表,加入到Close表中。
      • 遍歷該點(diǎn)A四周所有可到達(dá)節(jié)點(diǎn),如果這些節(jié)點(diǎn)不包含在Exist表中(即未出現(xiàn)過),則計(jì)算它們的F值,并且根據(jù)F值大小順序加入到Open表中。

        alt textalt text
      • 記錄這些點(diǎn)的父節(jié)點(diǎn)為該點(diǎn)A。

        alt text

      2.2 第二輪操作

      • 在第一輪操作結(jié)束后的Open表中,將隊(duì)首節(jié)點(diǎn)(即F值最小的節(jié)點(diǎn))移出Open表,加入到Close表中。
      • 遍歷該點(diǎn)B四周所有可到達(dá)節(jié)點(diǎn),如果這些節(jié)點(diǎn)不包含在Exist表中(即未出現(xiàn)過),則計(jì)算它們的F值,并且根據(jù)F值大小順序加入到Open表中。
      • (3,3)節(jié)點(diǎn)為障礙物,(3,1)節(jié)點(diǎn)已被Exist表包含,所以兩個(gè)點(diǎn)都不加入到Open表中。

        alt textalt text
      • 記錄新加入這些點(diǎn)的父節(jié)點(diǎn)為該點(diǎn)B。

        alt text

      3. A*算法實(shí)現(xiàn)代碼

      3.1 定義Node類

      • init_Node(Father,end):傳入父節(jié)點(diǎn)和終點(diǎn),并計(jì)算兩者間的曼哈頓距離,最終根據(jù)公式算出該點(diǎn)的F值。
      • compareTo(Node):用于比較出F值最小的點(diǎn)
      class Node implements Comparable<Node> {
          public int x;  //x坐標(biāo)
          public int y;  //y坐標(biāo)
          public int F;  //F屬性
          public int G;  //G屬性
          public int H;  //H屬性
          public Node Father;    //此結(jié)點(diǎn)的上一個(gè)結(jié)點(diǎn)
          //獲取當(dāng)前結(jié)點(diǎn)的坐標(biāo)
          public Node(int x, int y) {
              this.x = x;
              this.y = y;
          }
          //通過結(jié)點(diǎn)的坐標(biāo)可以得到F, G, H三個(gè)屬性
          //需要傳入這個(gè)節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)和最終的結(jié)點(diǎn)
          public void init_node(Node father, Node end) {//father是父節(jié)點(diǎn)
              this.Father = father;
              if (this.Father != null) {
                  this.G = father.G + 1;
              } else { //父節(jié)點(diǎn)為空代表它是第一個(gè)結(jié)點(diǎn)
                  this.G = 0;
              }
              //計(jì)算通過現(xiàn)在的結(jié)點(diǎn)的位置和最終結(jié)點(diǎn)的位置計(jì)算H值
              this.H = Math.abs(this.x - end.x) + Math.abs(this.y - end.y);
              this.F = this.G + this.H;
          }
          // 用來進(jìn)行和其他的Node類進(jìn)行比較
          @Override
          public int compareTo(Node o) {
              return Integer.compare(this.F, o.F);
          }
      }
      

      3.2 Solution方法

      • is_exist方法:判斷是否在Exist表中出現(xiàn)過。
      public boolean is_exist(Node node)
          {
              for (Node exist_node : Exist) {
                  if (node.x == exist_node.x && node.y == exist_node.y) {
                      return true;
                  }
              }
              return false;
          }
      
      • is_valid方法:判斷是否合法(邊界,不可達(dá)點(diǎn),已存在于Exist表中都為不合法)
      public boolean is_valid(int x, int y) {
              // 如果結(jié)點(diǎn)的位置是-1,則不合法
              if (map[x][y] == -1) return false;
              for (Node node : Exist) {
                  //如果結(jié)點(diǎn)出現(xiàn)過,不合法
      //            if (node.x == x && node.y == y) {
      //                return false;
      //            }
                  if (is_exist(new Node(x, y))) {
                      return false;
                  }
              }
              //以上情況都沒有則合法
              return true;
          }
      
      • extend_current_node方法:遍歷該點(diǎn)的上下左右四個(gè)方向,并判斷這些點(diǎn)是否合法。
      public ArrayList<Node> extend_current_node(Node current_node) {
              int x = current_node.x;
              int y = current_node.y;
              ArrayList<Node> neighbour_node = new ArrayList<Node>();
              if (is_valid(x + 1, y))
              {
                  Node node = new Node(x + 1, y);
                  neighbour_node.add(node);
              }
              if (is_valid(x - 1, y))
              {
                  Node node = new Node(x -1, y);
                  neighbour_node.add(node);
              }
              if (is_valid(x, y + 1))
              {
                  Node node = new Node(x, y + 1);
                  neighbour_node.add(node);
              }
              if (is_valid(x, y - 1))
              {
                  Node node = new Node(x, y - 1);
                  neighbour_node.add(node);
              }
              return neighbour_node;
          }
      
      • astarSearch方法:A*算法具體實(shí)現(xiàn)方法。
      public Node astarSearch(Node start, Node end) {
              //把第一個(gè)開始的結(jié)點(diǎn)加入到Open表中
              this.Open.add(start);
              //把出現(xiàn)過的結(jié)點(diǎn)加入到Exist表中
              this.Exist.add(start);
              //主循環(huán)
              while (Open.size() > 0) {
                  //取優(yōu)先隊(duì)列頂部元素并且把這個(gè)元素從Open表中刪除
                  Node current_node = Open.poll();
                  //將這個(gè)結(jié)點(diǎn)加入到Close表中
                  Close.add(current_node);
                  //對(duì)當(dāng)前結(jié)點(diǎn)進(jìn)行擴(kuò)展,得到一個(gè)四周結(jié)點(diǎn)的數(shù)組
                  ArrayList<Node> neighbour_node = extend_current_node(current_node);
                  //對(duì)這個(gè)結(jié)點(diǎn)遍歷,看是否有目標(biāo)結(jié)點(diǎn)出現(xiàn)
                  //沒有出現(xiàn)目標(biāo)結(jié)點(diǎn)再看是否出現(xiàn)過
                  for (Node node : neighbour_node) {
                      if (node.x == end.x && node.y == end.y) {//找到目標(biāo)結(jié)點(diǎn)就返回
                          node.init_node(current_node,end);
                          return node;//返回的是終止結(jié)點(diǎn)
                      }
                      if (!is_exist(node)) {  //沒出現(xiàn)過的結(jié)點(diǎn)加入到Open表中并且設(shè)置父節(jié)點(diǎn)
                          node.init_node(current_node, end);
                          Open.add(node);
                          Exist.add(node);
                      }
                  }
              }
              //如果遍歷完所有出現(xiàn)的結(jié)點(diǎn)都沒有找到最終的結(jié)點(diǎn),返回null
              return null;
          }
      

      3.3 main方法

      • 繪制8*8地圖,并設(shè)置好起點(diǎn)和終點(diǎn)(原文直接在地圖中進(jìn)行起點(diǎn)終點(diǎn)的設(shè)置,修改起點(diǎn)和終點(diǎn)時(shí)相對(duì)麻煩,我在這里對(duì)原文進(jìn)行了改進(jìn),在代碼中設(shè)置起點(diǎn)終點(diǎn),測(cè)試不同種情況時(shí)相對(duì)便捷)。
      int[][] map = {
                      {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
                      {-1,  0,  0,  0,  0,  0,  0,  0,  0, -1},
                      {-1,  0,  0,  0,  0, -1,  0,  0,  0, -1},
                      {-1,  0,  0,  0, -1,  0,  0,  0,  0, -1},
                      {-1,  0,  0,  0, -1,  0,  0,  0,  0, -1},
                      {-1,  0,  0,  0,  0, -1,  0,  0,  0, -1},
                      {-1,  0,  0,  0, -1,  0,  0,  0,  0, -1},
                      {-1,  0,  0,  0,  0, -1,  0,  0,  0, -1},
                      {-1,  0,  0,  0,  0,  0,  0,  0,  0, -1},
                      {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
              };
              Node start = new Node(4, 2);
              map[start.x][start.y]=1;
              start.Father = null;
              Node end = new Node(4, 7);
              map[end.x][end.y]=2;
      
      • 調(diào)用Solution函數(shù),拿到最短路徑
      Solution solution = new Solution();
              Node res_node = solution.astarSearch(start, end);//res—node最先接收的是該地圖的終止
              while (res_node != null) {
                  map[res_node.x][res_node.y] = res_node.G;
                  res_node = res_node.Father;//迭代操作,從終止結(jié)點(diǎn)開始向后退,直到起點(diǎn)的父節(jié)點(diǎn)為null。循環(huán)終止
              }
      
      • 輸出路徑,我在這里對(duì)輸出地圖進(jìn)行了一定程度上的渲染,紅色代表邊界和障礙不可達(dá)點(diǎn),綠色代表起點(diǎn)和終點(diǎn),藍(lán)色代表路徑,數(shù)字代表所走的步數(shù)(我在這里進(jìn)行了改進(jìn),使輸出地圖更加直觀)。
      //渲染迷宮
              for (int i = 0; i < 10; i++)
              {
                  for (int j = 0; j < 10; j++)
                  {
                      Node nownode =new Node(i,j);
                      if(map[i][j]==-1)
                          System.out.printf("\033[31m%3d\033[0m", map[i][j]);//red
                      else if (equal_node(nownode,start) || equal_node(nownode,end))
                          System.out.printf("\033[32m%3d\033[0m", map[i][j]);//green
                      else if(map[i][j]==0 && !equal_node(nownode,start))
                          System.out.printf("%3d", map[i][j]);//black
                      else
                          System.out.printf("\033[34m%3d\033[0m", map[i][j]);//blue
                  }
                  System.out.println();
              }
      

      3.4 輸出結(jié)果


      Image

      源代碼已保存到課題組github文件夾

      posted @ 2024-09-24 14:02  WUST許志偉  閱讀(42)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 性做久久久久久久久| 亚洲av激情综合在线| 又黄又爽又无遮挡免费的网站| 熟女蜜臀av麻豆一区二区| 精品偷拍一区二区三区| 人妻va精品va欧美va| 精品黄色av一区二区三区| 日韩乱码人妻无码中文字幕视频| 国产色无码专区在线观看| 久热这里只有精品视频3| 亚洲肥老太bbw中国熟女| 色吊丝免费av一区二区| 国产乱理伦片在线观看| 亚洲av乱码久久亚洲精品| 久久精品国产99国产精品澳门| 日韩黄色av一区二区三区| 国产精品无码无需播放器| 成人片黄网站色大片免费毛片 | 五月开心六月丁香综合色啪| 九九在线精品国产| 国产在线中文字幕精品| 日韩av一区二区精品不卡| 国产一区二区高清不卡| www夜插内射视频网站| a男人的天堂久久a毛片| 国内精品久久人妻无码不卡| 亚州少妇无套内射激情视频| 亚洲精品国产精品国在线 | 欧洲精品码一区二区三区| 亚洲无码a∨在线视频| 另类 专区 欧美 制服| 国产成人精品午夜2022| 国产中文字幕久久黄色片| 奇米四色7777中文字幕| 日韩少妇人妻vs中文字幕| 性色在线视频精品| 大伊香蕉精品一区二区| 色综合久久中文综合久久激情| 国产精品成人av在线观看春天| 成人区人妻精品一区二区| 国产精品一区中文字幕|