<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          “走迷宮”教學(xué)思路

          共 7249字,需瀏覽 15分鐘

           ·

          2023-02-25 12:27

          說(shuō)在前面

          “走迷宮”是一個(gè)經(jīng)典的算法問(wèn)題:給定二維地圖、入口和出口坐標(biāo),查找行走路徑(或最短路徑)。常見思路是使用深搜或廣搜算法來(lái)尋找路徑。

          浙教版《信息技術(shù)選擇性必修1數(shù)據(jù)與數(shù)據(jù)結(jié)構(gòu)》5.2.2 遞歸中有一個(gè)“實(shí)踐與體驗(yàn)”,項(xiàng)目名稱是“走迷宮”,給定二維地圖、入口和出口坐標(biāo),要求編程判斷是否能從出口走出,即判斷入口和出口是否連通。

          相比輸出路徑,本題的難度降低了。教材程序采用簡(jiǎn)單的遞歸算法解決了該問(wèn)題,思路清晰、代碼簡(jiǎn)潔,對(duì)于鞏固學(xué)生對(duì)遞歸算法的理解很有幫助。教師在教學(xué)中可以引導(dǎo)學(xué)生理解教材程序中各語(yǔ)句和變量的含義,分析程序輸出兩行“successful!”的原因,并思考如何對(duì)代碼加以改進(jìn),如何使用非遞歸算法來(lái)解決此問(wèn)題。

          教材文本

          教材處理

          教材給出了“走迷宮”案例的實(shí)踐步驟,并提供了完整源代碼和測(cè)試數(shù)據(jù)示意圖。教師除了引導(dǎo)學(xué)生分析示意圖,理解算法思想,還應(yīng)該結(jié)合代碼,幫助學(xué)生分析程序是如何實(shí)現(xiàn)算法思想的,是否有其他的算法設(shè)計(jì)和代碼實(shí)現(xiàn)方式。

          總體來(lái)說(shuō),書中程序算法邏輯清晰,代碼簡(jiǎn)潔明了,值得學(xué)生認(rèn)真體會(huì)。同時(shí),教師可以趁熱打鐵,在例題的基礎(chǔ)上做進(jìn)一步拓展,引導(dǎo)學(xué)生分析例題代碼的不足之處,思考改進(jìn)方法,并回顧之前學(xué)習(xí)過(guò)的棧和隊(duì)列,思考解決“走迷宮”問(wèn)題的非遞歸算法。

          學(xué)生任務(wù)單

          閱讀教材P125實(shí)踐與體驗(yàn)“走迷宮”,思考如下問(wèn)題:
          (1)書中程序使用二維數(shù)組maze存儲(chǔ)迷宮圖案,則len(maze)和len(maze[0])分別表示什么?
          (2)二維數(shù)組maze是用橫軸坐標(biāo)還是行列坐標(biāo)來(lái)描述元素位置的?遞歸函數(shù)walk的形式參數(shù)x和y分別表示什么?
          (3)maze[x][y]表示什么?當(dāng)其取值為0、1、2時(shí)分別有何含義?
          (4)遞歸函數(shù)walk的遞歸出口和遞歸體分別怎么表示? 
          (5)運(yùn)行書中程序后,輸出了兩行“successful!”,這是為什么?另外,當(dāng)入口與出口不連通時(shí),書中程序不會(huì)輸出任何結(jié)果,你能否對(duì)程序加以改進(jìn),使其在找到出口時(shí)只輸出一行“successful!”,并在找不到出口時(shí),輸出“failed!”。
          (6)如下程序能實(shí)現(xiàn)問(wèn)題(5)的功能,試比較其與教材程序的異同,并做進(jìn)一步簡(jiǎn)化。
          #判斷坐標(biāo)有效性的函數(shù)
          def valid(maze, r, c):
              return 0 <= r < len(maze) and 0 <= c < len(maze[0]) and maze[r][c] == 1
          #移步函數(shù)
          def walk(maze, r, c):
              #如果位置是迷宮的出口,說(shuō)明成功走出迷宮
              if r == 8 and c == 8:
                  return True
              #遞歸體
              if valid(maze, r, c):
                  maze[r][c] = 2 #做標(biāo)記,防止折回 
                  #依次向上左下右四個(gè)方向試探,若找到出口,則結(jié)束查找
                  if walk(maze,r-1,c): 
                      return True
                  if walk(maze,r,c-1):
                      return True
                  if walk(maze,r+1,c):
                      return True
                  if walk(maze,r,c+1):
                      return True
              return False # 未找到迷宮出口,返回False
          #主函數(shù)部分
          #為maze賦值,代碼略
          if walk(maze, 1, 1):
              print("successful!")
          else:
              print("failed!")
          (7)計(jì)算機(jī)在執(zhí)行遞歸程序時(shí),是通過(guò)棧的調(diào)用來(lái)實(shí)現(xiàn)的。遞歸程序是將復(fù)雜問(wèn)題分解為一系列簡(jiǎn)單的問(wèn)題,從要解的問(wèn)題起,逐步分解,并將每步分解得到的問(wèn)題放入“?!敝?,運(yùn)用棧的“后進(jìn)先出”的性質(zhì),這樣棧頂是最后分解得到的最簡(jiǎn)單的問(wèn)題,解決了這個(gè)問(wèn)題后,次簡(jiǎn)單的問(wèn)題可以得到答案,以此類推。所以,分解問(wèn)題可以看作是進(jìn)棧的過(guò)程,而解決問(wèn)題則是出棧的過(guò)程。

          我們可以根據(jù)這個(gè)原理,通過(guò)構(gòu)造一個(gè)棧,采用非遞歸算法來(lái)解決走迷宮問(wèn)題,參考代碼如下(僅對(duì)walk函數(shù)做了修改,其他代碼不變),請(qǐng)將缺失的代碼補(bǔ)充完整。

          def walk(maze, r, c):
              if r == 8 and c == 8:
                  return True
              st = [] #用來(lái)記錄路徑點(diǎn)坐標(biāo)和朝向的棧
              #分別向上左下右移動(dòng)的行列坐標(biāo)變換情況
              dirs = [[-1, 0],[0, -1],[1, 0],[0, 1]] 
              maze[r][c] = 2 #做標(biāo)記,防止折回
              st.append([r, c, 0]) #將起點(diǎn)坐標(biāo)和初始朝向均入棧
              while len(st) > 0:
                  r, c, nextd = st.pop()  
                  for i in range(nextd, 4): #依次檢查棧頂元素未探查方向
                      nextr = 填空1
                      nextc = 填空2
                      if nextr == 8 and nextc == 8: #若找到出口,則結(jié)束查找
                          return True
                      if valid(填空3):
                          maze[nextr][nextc] = 2 #做標(biāo)記,防止折回
                          st.append([r, c, i+1]) #原位置和其下一方向入棧
                          st.append(填空4)       #新位置和初始朝向入棧

                          break #退出內(nèi)層循環(huán),處理下一位置

              return False

          問(wèn)題解析

          (1)len(maze)表示總的行數(shù),len(maze[0])表示總的列數(shù)。
          (2)二維數(shù)組maze是用行列坐標(biāo)來(lái)描述元素位置的,參數(shù)x和y分別表示迷宮中某個(gè)位置的行、列坐標(biāo)。將參數(shù)命名為x和y不太好,因?yàn)闀?huì)讓人誤以為是平面直角坐標(biāo)系中的橫縱坐標(biāo),最好將參數(shù)改名為r和c,表示行列坐標(biāo)。
          (3)maze[x][y]表示第x行第y列的坐標(biāo)點(diǎn)的值,當(dāng)其取值為0、1、2時(shí)分別表示不可通行、可通行、已查找。
          (4)遞歸出口:當(dāng)(x==8 and y==8)時(shí),執(zhí)行print("successful!"),并返回True。

          遞歸體:當(dāng)valid(maze, x, y)為True時(shí),先設(shè)置maze[x][y] = 2,再針對(duì)四個(gè)方向依次試探,分4次遞歸調(diào)用函數(shù)walk。

          (5)程序輸出了兩行“successful!”,說(shuō)明通過(guò)2條獨(dú)立的路徑找到了出口。應(yīng)該在調(diào)用walk函數(shù)時(shí)判斷是否找到出口,若找到出口則直接返回True,停止試探下一方向。

          可以對(duì)walk函數(shù)加以改進(jìn),使其在找到出口時(shí)返回True,否則返回False。然后在主函數(shù)中,根據(jù)walk函數(shù)的返回值決定輸出 “successful!”或“failed!”。

          (6)walk函數(shù)的遞歸體部分采用順序結(jié)構(gòu)依次向上左下右四個(gè)方向試探,代碼有些重復(fù),可以設(shè)置一個(gè)二維數(shù)組dirs,存儲(chǔ)分別向上左下右移動(dòng)的行列坐標(biāo)變換情況,通過(guò)循環(huán)遍歷dirs,將代碼做進(jìn)一步簡(jiǎn)化。參考代碼如下:
          def walk(maze, r, c):
              #如果位置是迷宮的出口,說(shuō)明成功走出迷宮
              if r == 8 and c == 8:
                  return True
              #遞歸體
              if valid(maze, r, c):
                  maze[r][c] = 2 #做標(biāo)記,防止折回
                  #分別向上左下右移動(dòng)的行列坐標(biāo)變換情況
                  dirs = [[-1, 0],[0, -1],[1, 0],[0, 1]] 
                  #依次向上左下右四個(gè)方向試探,若找到出口,則結(jié)束查找
                  for d in dirs:
                      if walk(maze,r+d[0],c+d[1]): 
                          return True
              return False # 未找到迷宮出口,返回False
          (7)參考代碼如下(僅對(duì)walk函數(shù)做了修改,其他代碼不變):
          def walk(maze, r, c): #用棧實(shí)現(xiàn)深度優(yōu)先搜索
              #如果位置是迷宮的出口,說(shuō)明成功走出迷宮
              if r == 8 and c == 8:
                  return True
              st = [] #用來(lái)記錄路徑點(diǎn)坐標(biāo)和朝向的棧
              #分別向上左下右移動(dòng)的行列坐標(biāo)變換情況
              dirs = [[-1, 0],[0, -1],[1, 0],[0, 1]] 
              maze[r][c] = 2 #做標(biāo)記,防止折回
              st.append([r, c, 0]) #將起點(diǎn)坐標(biāo)和初始朝向均入棧
              while len(st) > 0:
                  r, c, nextd = st.pop() #退棧,并讀取棧頂元素的坐標(biāo)和朝向
                  for i in range(nextd, 4): #依次檢查棧頂元素未探查方向
                      nextr, nextc = r+dirs[i][0], c+dirs[i][1]
                      if nextr == 8 and nextc == 8: #若找到出口,則結(jié)束查找
                          return True
                      if valid(maze, nextr, nextc):
                          maze[nextr][nextc] = 2 #做標(biāo)記,防止折回
                          st.append([r, c, i+1]) #原位置和其下一方向入棧
                          st.append([nextr, nextc, 0]) #新位置和初始朝向入棧
                          break #退出內(nèi)層循環(huán),處理下一位置
              return False

          課后作業(yè)

          任務(wù)(7)通過(guò)構(gòu)造一個(gè)棧來(lái)解決走迷宮問(wèn)題的算法被稱為深度優(yōu)先搜索算法,其特點(diǎn)是先沿著一個(gè)方向不斷向前查找,直到找到終點(diǎn)或此路不通為止,若某位置不通了,則退回上一位置,換個(gè)方向繼續(xù)查找。

          除此之外,還有一種被稱為廣度優(yōu)先搜索的算法,它通過(guò)構(gòu)造一個(gè)隊(duì)列來(lái)存儲(chǔ)途徑點(diǎn)的坐標(biāo),每次查找都先把當(dāng)前位置的相鄰點(diǎn)加入隊(duì)列,直到找到終點(diǎn)或隊(duì)列為空。此種算法需要占據(jù)較多空間,但是能找到最短路徑,效率較高。參考代碼如下(僅對(duì)walk函數(shù)做了修改,其他代碼不變),請(qǐng)將缺失的代碼補(bǔ)充完整。

          def walk(maze, r, c): #用隊(duì)列實(shí)現(xiàn)廣度優(yōu)先搜索

              #如果位置是迷宮的出口,說(shuō)明成功走出迷宮

              if r == 8 and c == 8:

                  return True

              from queue import Queue  #引入queue模塊FIFO隊(duì)列Queue

              q = Queue() #用來(lái)記錄路徑點(diǎn)坐標(biāo)的隊(duì)列

              #分別向上左下右移動(dòng)的行列坐標(biāo)變換情況

              dirs = [[-1, 0],[0, -1],[1, 0],[0, 1]] 

              maze[r][c] = 2 #做標(biāo)記,防止折回

              q.put([r, c]) #將入口位置入列

              while not q.emptue():

                  r, c = q.get()

                  for i in range(4): #依次檢查四個(gè)方向

                      nextr = 填空1

                      nextc = 填空2

                      if nextr == 8 and nextc == 8: #若找到出口,則結(jié)束查找

                          return True

                      if valid(填空3):

                          maze[nextr][nextc] = 2 #做標(biāo)記,防止折回

                          q.put(填空4)

              return False


          需要本文word文檔、源代碼和課后思考答案的,可以加入“Python算法之旅”知識(shí)星球參與討論和下載文件,Python算法之旅”知識(shí)星球匯集了數(shù)量眾多的同好,更多有趣的話題在這里討論,更多有用的資料在這里分享。

          我們專注Python算法,感興趣就一起來(lái)!


          相關(guān)優(yōu)秀文章:
          閱讀代碼和寫更好的代碼
          最有效的學(xué)習(xí)方式
          Python算法之旅文章分類

          瀏覽 57
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  婷婷五月天婷婷五月天婷婷五月天色 | 中国色情一级视频 | 又紧又嫩又爽无遮挡免费 | 久久国产亲子 | 中文字幕一区二区三区四区欧美 |