主頁 >  其他 > A*演算法(超級詳細講解,附有舉例的詳細手寫步驟)

A*演算法(超級詳細講解,附有舉例的詳細手寫步驟)

2020-11-18 12:00:03 其他

背景:專案需要接觸此演算法,以下是一些自學成果,如有不足之處,歡迎指出,必虛心接受,做了一份PPT來匯報,此處直接使用自己PPT的截圖,部分圖片來源網路,如有侵權立馬洗掉,以下博文僅作為學習筆記,

目錄

A*尋路演算法

A*演算法解決什么問題

A*演算法的基本原理

A*演算法的詳細原理

A*演算法的詳細原理之定義

?A*演算法的詳細原理之初始設定

?A*演算法的詳細原理之尋路原理

A*演算法的詳細原理之結束條件

A*演算法的尋路詳細步驟

A*演算法的舉例說明

A*演算法的偽代碼

A*演算法的定義偽代碼 (C++)

A*演算法的尋路偽代碼(C++)

Python+PyQt代碼實作

代碼內容(可運行)

運行結果

可執行檔案


A*尋路演算法

A*演算法解決什么問題

A*演算法的基本原理

A*演算法的詳細原理

A*演算法的詳細原理之定義

A*演算法的詳細原理之初始設定

A*演算法的詳細原理之尋路原理

A*演算法的詳細原理之結束條件

A*演算法的尋路詳細步驟

S(start)起點 E(End)終點

A*演算法的舉例說明

如果還不懂的話,可以參考我手寫的計算步驟,再不懂可以私信我,(手稿字有點丑)

A*演算法的偽代碼

A*演算法的定義偽代碼 (C++)

//定義
int G;// 表示從起點 A 移動到網格上指定方格的移動耗費 (上下左右,還可沿斜方向移動)
int old_G;//舊G 第一次:從起點 A 直接移動到 A 四周方格的移動耗費 ;上次更新得到的G 
int new_G; //新G  從起點 A 經過當前搜索中心點到其四周指定點的移動耗費 
int H;//表示從指定的方格移動到終點 B 的預計耗費 (H 有很多計算方法, 這里我們設定只可以上下左右移動)
int F=G+H;//表示該點的總耗費
int open_list//一個記錄下所有被考慮來尋找最短路徑的格子
int close_list //一個記錄下不會再被考慮的格子
typedef struct point{
	bool Is_Wall;
	struct point* father;//父節點
}Point;
point* start_point;
point* end_point
point* min_point; 
point* now_point; 

A*演算法的尋路偽代碼(C++)

//FindPath
do{
	//確定中心搜索點,上一個中心點關閉,新的中心點開啟 
	查找:Find the minimumm "point" of "F" from the "open_list" center
	"now_point" = "min_point";//minimumm point 
	"now_point"添加到"close_list";
	
	//新中心點的周圍點開啟,新中心點關閉 
	回圈遍歷:"now_point"相鄰的周圍8格"s_now_point"中的每一個
	//這一塊它指的就是now_point周圍8點當前搜索點 s_now_point,為了簡單直接用它表示 
	if (它不可通過||它已經在"close_list"中){
		什么也不做;
	} else if (它不在開啟串列中){
		把它添加進"open_list";
		把"now_point"作為這它的"father",計算它的"F","G","H";
	}else if (它已經在開啟串列中){//通過G來判斷是否需要更新 
		if (new_G < old_G){
			更新它的"father"為當前中心搜索點"now_point";
			更新它的"G"與"F" ;
		} else{
			不更新,保持原來的"father", "G"與"F" ;
		} 
	}
} while(目標格"end_point"已經在"open_list"||"open_list"==NULL)
//存在路徑:目標格"end_point"已經在"open_list"
//不存在路徑: "open_list"==NULL,搜索了所有可能的點 

Python+PyQt代碼實作

代碼內容(可運行)

import time,sys
from PyQt5.QtWidgets import QDialogButtonBox,QDialog,QMainWindow,QGridLayout,QTextEdit,QLineEdit,QWidget, QMessageBox, QApplication,QLabel,QPushButton,QHBoxLayout,QVBoxLayout
from PyQt5.QtCore import Qt,QTimer,QObject,pyqtSignal,QBasicTimer
from PyQt5.QtGui import QPainter, QColor, QFont,QPen
import json
class config:
	WIDTH=20#地圖列數
	HEIGHT=20#地圖行數
	blockLength=30#繪制畫面時每一個節點方塊的邊長
class point:#點類(每一個唯一坐標只有對應的一個實體)
	_list=[]#儲存所有的point類實體
	_tag=True#標記最新創建的實體是否為_list中的已有的實體,True表示不是已有實體
	def __new__(cls,x,y):#重寫new方法實作對于同樣的坐標只有唯一的一個實體
		for i in point._list:
			if i.x==x and i.y==y:
				point._tag=False
				return i
		nt=super(point,cls).__new__(cls)
		point._list.append(nt)
		return nt
	def __init__(self,x,y):
		if point._tag:
			self.x=x
			self.y=y
			self.father=None
			self.F=0#當前點的評分  F=G+H
			self.G=0#起點到當前節點所花費的消耗
			self.cost=0#父節點到此節點的消耗
		else:
			point._tag=True
	@classmethod
	def clear(cls):#clear方法,每次搜索結束后,將所有點資料清除,以便進行下一次搜索的時候點資料不會沖突,
		point._list=[]
	def __eq__(self,T):#重寫==運算以便實作point類的in運算
		if type(self)==type(T):
			return (self.x,self.y)==(T.x,T.y)
		else:
			return False
	def __str__(self):
		return'(%d,%d)[F=%d,G=%d,cost=%d][father:(%s)]'%(self.x,self.y,self.F,self.G,self.cost,str((self.father.x,self.father.y)) if self.father!=None else 'null')
class A_Search:#核心部分,尋路類
	def __init__(self,arg_start,arg_end,arg_map):
		self.start=arg_start#儲存此次搜索的開始點
		self.end=arg_end#儲存此次搜索的目的點
		self.Map=arg_map#一個二維陣列,為此次搜索的地圖參考
		self.open=[]#開放串列:儲存即將被搜索的節點
		self.close=[]#關閉串列:儲存已經搜索過的節點
		self.result=[]#當計算完成后,將最終得到的路徑寫入到此屬性中
		self.count=0#記錄此次搜索所搜索過的節點數
		self.useTime=0#記錄此次搜索花費的時間--在此演示中無意義,因為process方法變成了一個逐步處理的生成器,統計時間無意義,
		#開始進行初始資料處理
		self.open.append(arg_start)
	def cal_F(self,loc):
		print('計算值:',loc)
		G=loc.father.G+loc.cost
		H=self.getEstimate(loc)
		F=G+H
		print("F=%d G=%d H=%d"%(F,G,H))
		return {'G':G,'H':H,'F':F}
	def F_Min(self):#搜索open串列中F值最小的點并將其回傳,同時判斷open串列是否為空,為空則代表搜索失敗
		if len(self.open)<=0:
			return None
		t=self.open[0]
		for i in self.open:
			if i.F<t.F:
				t=i
		return t
	def getAroundPoint(self,loc):#獲取指定點周圍所有可通行的點,并將其對應的移動消耗進行賦值,
		l=[(loc.x,loc.y+1,10),(loc.x+1,loc.y+1,14),(loc.x+1,loc.y,10),(loc.x+1,loc.y-1,14),(loc.x,loc.y-1,10),(loc.x-1,loc.y-1,14),(loc.x-1,loc.y,10),(loc.x-1,loc.y+1,14)]
		for i in l[::-1]:
			if i[0]<0 or i[0]>=config.HEIGHT or i[1]<0 or i[1]>=config.WIDTH:
				l.remove(i)
		nl=[]
		for i in l:
			if self.Map[i[0]][i[1]]==0:
				nt=point(i[0],i[1])
				nt.cost=i[2]
				nl.append(nt)
		return nl

	def addToOpen(self,l,father):#此次判斷的點周圍的可通行點加入到open串列中,如此點已經在open串列中則對其進行判斷,如果此次路徑得到的F值較之之前的F值更小,則將其父節點更新為此次判斷的點,同時更新F、G值,
		for i in l:
			if i not in self.open:
				if i not in self.close:
					i.father=father
					self.open.append(i)
					r=self.cal_F(i)
					i.G=r['G']
					i.F=r['F']
			else:
				tf=i.father
				i.father=father
				r=self.cal_F(i)
				if i.F>r['F']:
					i.G=r['G']
					i.F=r['F']
					# i.father=father
				else:
					i.father=tf
	def getEstimate(self,loc):#H :從點loc移動到終點的預估花費
		return (abs(loc.x-self.end.x)+abs(loc.y-self.end.y))*10
	def DisplayPath(self):#在此演示中無意義
		print('搜索花費的時間:%.2fs.迭代次數%d,路徑長度:%d'%(self.useTime,self.count,len(self.result)))
		if self.result!=None:
			for i in self.result:
				self.Map[i.x][i.y]=8
			for i in self.Map:
				for j in i:
					if j==0:
						print('%s'%'□',end='')
					elif j==1:
						print('%s'%'▽',end='')
					elif j==8:
						print('%s'%'★',end='')
				print('')
		else:
			print('搜索失敗,無可通行路徑')
	def process(self):#使用yield將process方法變成一個生成器,可以逐步的對搜索程序進行處理并回傳關鍵資料
		while True:
			self.count+=1
			tar=self.F_Min()#先獲取open串列中F值最低的點tar
			if tar==None:
				self.result=None
				self.count=-1
				break
			else:
				aroundP=self.getAroundPoint(tar)#獲取tar周圍的可用點串列aroundP
				self.addToOpen(aroundP,tar)#把aroundP加入到open串列中并更新F值以及設定父節點
				self.open.remove(tar)#將tar從open串列中移除
				self.close.append(tar)#已經迭代過的節點tar放入close串列中
				if self.end in self.open:#判斷終點是否已經處于open串列中
					e=self.end
					self.result.append(e)
					while True:
						e=e.father
						if e==None:
							break
						self.result.append(e)
					yield (tar,self.open,self.close)
					break

			# self.repaint()
			# print('回傳')
			yield (tar,self.open,self.close)
			time.sleep(5)#暫停
		self.useTime=time2-time1
class GameBoard(QMainWindow):#可視化類,pyqt5進行撰寫,
	def __init__(self):
		print('初始化地圖...')
		self.Map=[]
		for i in range(config.HEIGHT):
			col=[]
			for j in range(config.WIDTH):
				col.append(0)
			self.Map.append(col)
		self.startPoint=None
		self.endPoint=None
		self.search=None
		self.centerTimer=None
		self.yi=None
		self.special=None
		self.displayFlush=False
		super().__init__()
		print('初始化UI...')
		self.initUI()
	def initUI(self):
		#開始初始化UI部分
			#創建UI控制元件
		self.label_tips=QLabel("<p style='color:green'>使用說明:</p>右鍵單擊格子選定起始點,左鍵格子選定格子為墻壁或洗掉墻壁,\n<p style='color:green'>顏色說明:</p>\n黃色代表起點,綠色代表終點,黑色代表墻壁,紅色代表待搜索的open串列,灰色代表已搜索過的close串列,藍色代表當前搜索到的路徑",self)
		self.label_display=QLabel("",self)
		self.button_start=QPushButton("開始搜索",self)
		self.button_clearSE=QPushButton("重選起始點",self)
		self.button_clearWall=QPushButton("清空地圖墻壁",self)
		self.button_saveMap=QPushButton("保存地圖",self)
		self.button_loadMap=QPushButton("加載地圖",self)


			#設定控制元件屬性
		self.label_tips.setWordWrap(True)
		self.label_display.setWordWrap(True)
			#設定控制元件樣式
		self.label_display.setStyleSheet("border:1px solid black")
		self.label_display.setAlignment(Qt.AlignLeft)
		self.label_display.setAlignment(Qt.AlignTop)
			#設定控制元件的尺寸和位置
		self.label_tips.resize(200,150)
		self.button_saveMap.resize(80,30)
		self.button_loadMap.resize(80,30)
		self.label_display.resize(200,300)

		self.label_tips.move(100+(config.WIDTH-1)*config.blockLength,0)
		self.label_display.move(100+(config.WIDTH-1)*config.blockLength,400)
		self.button_start.move(100+(config.WIDTH-1)*config.blockLength,200)
		self.button_clearSE.move(100+(config.WIDTH-1)*config.blockLength,250)
		self.button_clearWall.move(100+(config.WIDTH-1)*config.blockLength,300)
		self.button_saveMap.move(100+(config.WIDTH-1)*config.blockLength,350)
		self.button_loadMap.move(200+(config.WIDTH-1)*config.blockLength,350)
			#給控制元件系結事件
		self.button_start.clicked.connect(self.button_StartEvent)
		self.button_clearSE.clicked.connect(self.button_Clear)
		self.button_clearWall.clicked.connect(self.button_Clear)
		self.button_saveMap.clicked.connect(self.button_SaveMap)
		self.button_loadMap.clicked.connect(self.button_LoadMap)
		#UI初始化完成
		self.setGeometry(0, 0, 150+(config.WIDTH*config.blockLength-config.blockLength)+200, 150+(config.HEIGHT*config.blockLength-config.blockLength))
		self.setMinimumSize(150+(config.WIDTH*config.blockLength-config.blockLength)+200, 150+(config.HEIGHT*config.blockLength-config.blockLength))
		self.setMaximumSize(150+(config.WIDTH*config.blockLength-config.blockLength)+200, 150+(config.HEIGHT*config.blockLength-config.blockLength))
		self.setWindowTitle('A*搜索')
		self.show()
	def addDisplayText(self,text):
		if self.displayFlush:
			self.label_display.setText(text+'\n')
			self.displayFlush=False
		else:
			self.label_display.setText(self.label_display.text()+text+'\n')
	def mousePressEvent(self,event):
		x,y=event.x()-50,event.y()-50
		x=x//config.blockLength
		y=y//config.blockLength
		if x>=0 and x<config.WIDTH and y>=0 and y<config.HEIGHT:
			if event.button()==Qt.LeftButton:
				if (x,y)!=self.startPoint and (x,y)!=self.endPoint:
					self.Map[y][x]=(1 if self.Map[y][x]==0 else 0)
			if event.button()==Qt.RightButton:
				if self.Map[y][x]==0:
					if self.startPoint==None:
						self.startPoint=(x,y)
						self.addDisplayText('添加了一個起點:(%d,%d)'%(x,y))
					elif self.endPoint==None and self.startPoint!=(x,y):
						self.endPoint=(x,y)
						self.addDisplayText('添加了一個終點:(%d,%d)'%(x,y))
			self.repaint()
	def button_StartEvent(self):
		sender=self.sender()
		print(sender)
		if self.startPoint!=None and self.endPoint!=None:
			if self.centerTimer==None:
				self.centerTimer=QBasicTimer()
			self.button_start.setEnabled(False)
			self.button_clearSE.setEnabled(False)
			self.button_clearWall.setEnabled(False)
			self.centerTimer.start(200,self)
			self.search=A_Search(point(self.startPoint[1],self.startPoint[0]),point(self.endPoint[1],self.endPoint[0]),self.Map)
			self.yi=self.search.process()
			self.addDisplayText('開始進行搜索')
	def button_SaveMap(self):
		with open('map.txt','w') as f:
			f.write(json.dumps(self.Map))
			self.addDisplayText('地圖保存成功-->map.txt')
		# else:
			# self.addDisplayText('地圖保存失敗')
	def button_LoadMap(self):
		try:
			with open('map.txt','r') as f:
				self.Map=json.loads(f.read())
				config.HEIGHT=len(self.Map)
				config.WIDTH=len(self.Map[0])
				self.addDisplayText('地圖加載成功')
				self.repaint()
		except Exception as e:
			print('失敗',e,type(e))
			if type(e)==FileNotFoundError:
				self.addDisplayText('地圖加載失敗:地圖檔案不存在')
			elif type(e)==json.decoder.JSONDecodeError:
				self.addDisplayText('地圖加載失敗:錯誤的地圖檔案')
	def button_Clear(self):
		sender=self.sender()
		print(self.button_clearSE,type(self.button_clearSE))
		if sender==self.button_clearSE:
			self.startPoint=None
			self.endPoint=None
			self.repaint()
			self.addDisplayText('清空起始點')
		elif sender==self.button_clearWall:
			for i in range(len(self.Map)):
				for j in range(len(self.Map[i])):
					self.Map[i][j]=0
			self.repaint()
			self.addDisplayText('清空所有墻壁')
	def paintEvent(self, event):
		qp = QPainter()
		qp.begin(self)
		self.drawBoard(event,qp)
		qp.end()
	def drawBoard(self, event, qp):
	    self.drawMap(qp)
	def drawMap(self,qp):#畫面繪制方法,每次地圖有所改動都將重繪
		time1=time.time()
		if self.search!=None:
			if self.special!=None:
				e=self.special[0]
				path=[e]
				while True:
					e=e.father
					if e!=None:
						path.append(e)
					else:
						break
			else:
				path=None
			pen=QPen(QColor(0,0,0),1,Qt.SolidLine)
			qp.setPen(pen)
			for i in range(len(self.Map)):
				for j in range(len(self.Map[i])):
					wordTag=False
					if i==self.search.start.x and j==self.search.start.y:
						qp.setBrush(QColor(255,255,0))
					elif i==self.search.end.x and j==self.search.end.y:
						qp.setBrush(QColor(100,200,50))
					else:
						if self.Map[i][j]==0:
							tagx=True
							if path:
								for k in path:
									if k.x==i and k.y==j:
										tagx=False
										qp.setBrush(QColor(0,100,255))
							if tagx:
								if self.special!=None:
									if i==self.special[0].x and j==self.special[0].y:
										qp.setBrush(QColor(0,255,0))
									else:
										tag=True
										for k in self.special[1]:
											if k.x==i and k.y==j:
												tag=False
												wordTag=True
												word=str(k.F)

												qp.setBrush(QColor(150,0,0))
												break
											else:
												qp.setBrush(QColor(220,220,220))
										if tag:
											for k in self.special[2]:
												if k.x==i and k.y==j:
													qp.setBrush(QColor(150,150,150))
													break
												else:
													qp.setBrush(QColor(220,220,220))
								else:
									qp.setBrush(QColor(220,220,220))
						elif self.Map[i][j]==1:
							qp.setBrush(QColor(0,0,0))
						else:
							qp.setBrush(QColor(255,0,0))
					qp.drawRect(50+j*config.blockLength,50+i*config.blockLength,config.blockLength,config.blockLength)
					if wordTag:
						qp.setFont(QFont('楷體',5,QFont.Light))
						qp.drawText(50+10+j*config.blockLength,50+10+i*config.blockLength,word)
						wordTag=False
		#time.sleep(20)
		else:
			for i in range(len(self.Map)):
				for j in range(len(self.Map[i])):
					if (j,i)==self.startPoint:
						qp.setBrush(QColor(255,255,0))
					elif (j,i)==self.endPoint:
						qp.setBrush(QColor(100,200,50))
					else:
						if self.Map[i][j]==0:
							qp.setBrush(QColor(220,220,220))
						elif self.Map[i][j]==1:
							qp.setBrush(QColor(0,0,0))
						else:
							qp.setBrush(QColor(255,0,0))

					qp.drawRect(50+j*config.blockLength,50+i*config.blockLength,config.blockLength,config.blockLength)
		time2=time.time()
	#time.sleep(20)
		# print('繪制時間:',time2-time1)
	def timerEvent(self,e):
		try:
			data=next(self.yi)
		except Exception as e:
			self.addDisplayText('搜索結束:')
			print('搜索結束!')
			if self.search.result==None:
				self.addDisplayText('未找到可行路徑')
				print('搜索結束!')
			else:
				self.addDisplayText('總計搜索節點數:%d'%self.search.count)
				self.addDisplayText('最終路徑長度:%d'%len(self.search.result))
			self.centerTimer.stop()
			self.search=None
			self.yi=None
			self.special=None
			point.clear()
			self.button_start.setEnabled(True)
			self.button_clearSE.setEnabled(True)
			self.button_clearWall.setEnabled(True)
			self.displayFlush=True
		else:
			self.special=data
			self.repaint()
if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = GameBoard()
	sys.exit(app.exec_())

注意:代碼運行可以設定動態遍歷的時候暫停時間(大概在145行的time.sleep(5)陳述句)

運行結果

輸出每次計算的每個點的F和父結點,直接看圖吧!

詳細串列

初始化地圖...
初始化UI...
<PyQt5.QtWidgets.QPushButton object at 0x0000017CC699AC18>
計算值: (2,3)[F=0,G=0,cost=10][father:((2, 2))]
F=40 G=10 H=30
計算值: (3,3)[F=0,G=0,cost=14][father:((2, 2))]
F=54 G=14 H=40
計算值: (3,2)[F=0,G=0,cost=10][father:((2, 2))]
F=60 G=10 H=50
計算值: (3,1)[F=0,G=0,cost=14][father:((2, 2))]
F=74 G=14 H=60
計算值: (2,1)[F=0,G=0,cost=10][father:((2, 2))]
F=60 G=10 H=50
計算值: (1,1)[F=0,G=0,cost=14][father:((2, 2))]
F=74 G=14 H=60
計算值: (1,2)[F=0,G=0,cost=10][father:((2, 2))]
F=60 G=10 H=50
計算值: (1,3)[F=0,G=0,cost=14][father:((2, 2))]
F=54 G=14 H=40
計算值: (3,3)[F=54,G=14,cost=10][father:((2, 3))]
F=60 G=20 H=40
計算值: (3,2)[F=60,G=10,cost=14][father:((2, 3))]
F=74 G=24 H=50
計算值: (1,2)[F=60,G=10,cost=14][father:((2, 3))]
F=74 G=24 H=50
計算值: (1,3)[F=54,G=14,cost=10][father:((2, 3))]
F=60 G=20 H=40
計算值: (4,4)[F=0,G=0,cost=14][father:((3, 3))]
F=68 G=28 H=40
計算值: (4,3)[F=0,G=0,cost=10][father:((3, 3))]
F=74 G=24 H=50
計算值: (4,2)[F=0,G=0,cost=14][father:((3, 3))]
F=88 G=28 H=60
計算值: (3,2)[F=60,G=10,cost=10][father:((3, 3))]
F=74 G=24 H=50
計算值: (1,2)[F=60,G=10,cost=10][father:((1, 3))]
F=74 G=24 H=50
計算值: (0,2)[F=0,G=0,cost=14][father:((1, 3))]
F=88 G=28 H=60
計算值: (0,3)[F=0,G=0,cost=10][father:((1, 3))]
F=74 G=24 H=50
計算值: (0,4)[F=0,G=0,cost=14][father:((1, 3))]
F=68 G=28 H=40
計算值: (4,3)[F=74,G=24,cost=14][father:((3, 2))]
F=74 G=24 H=50
計算值: (4,2)[F=88,G=28,cost=10][father:((3, 2))]
F=80 G=20 H=60
計算值: (4,1)[F=0,G=0,cost=14][father:((3, 2))]
F=94 G=24 H=70
計算值: (3,1)[F=74,G=14,cost=10][father:((3, 2))]
F=80 G=20 H=60
計算值: (2,1)[F=60,G=10,cost=14][father:((3, 2))]
F=74 G=24 H=50
計算值: (3,1)[F=74,G=14,cost=10][father:((2, 1))]
F=80 G=20 H=60
計算值: (3,0)[F=0,G=0,cost=14][father:((2, 1))]
F=94 G=24 H=70
計算值: (2,0)[F=0,G=0,cost=10][father:((2, 1))]
F=80 G=20 H=60
計算值: (1,0)[F=0,G=0,cost=14][father:((2, 1))]
F=94 G=24 H=70
計算值: (1,1)[F=74,G=14,cost=10][father:((2, 1))]
F=80 G=20 H=60
計算值: (1,2)[F=60,G=10,cost=14][father:((2, 1))]
F=74 G=24 H=50
計算值: (1,1)[F=74,G=14,cost=10][father:((1, 2))]
F=80 G=20 H=60
計算值: (0,1)[F=0,G=0,cost=14][father:((1, 2))]
F=94 G=24 H=70
計算值: (0,2)[F=88,G=28,cost=10][father:((1, 2))]
F=80 G=20 H=60
計算值: (0,3)[F=74,G=24,cost=14][father:((1, 2))]
F=74 G=24 H=50
計算值: (4,5)[F=0,G=0,cost=10][father:((4, 4))]
F=68 G=38 H=30
計算值: (5,5)[F=0,G=0,cost=14][father:((4, 4))]
F=82 G=42 H=40
計算值: (5,4)[F=0,G=0,cost=10][father:((4, 4))]
F=88 G=38 H=50
計算值: (5,3)[F=0,G=0,cost=14][father:((4, 4))]
F=102 G=42 H=60
計算值: (4,3)[F=74,G=24,cost=10][father:((4, 4))]
F=88 G=38 H=50
計算值: (3,5)[F=0,G=0,cost=14][father:((4, 4))]
F=62 G=42 H=20
計算值: (3,6)[F=0,G=0,cost=10][father:((3, 5))]
F=62 G=52 H=10
計算值: (4,6)[F=0,G=0,cost=14][father:((3, 5))]
F=76 G=56 H=20
計算值: (4,5)[F=68,G=38,cost=10][father:((3, 5))]
F=82 G=52 H=30
計算值: (2,5)[F=0,G=0,cost=10][father:((3, 5))]
F=62 G=52 H=10
計算值: (2,6)[F=0,G=0,cost=14][father:((3, 5))]
F=56 G=56 H=0
搜索結束!

可執行檔案

已經將程式打包成exe可執行檔案,點擊即可用,不需要py環境,

鏈接:https://pan.baidu.com/s/1TzFK0ODsf1JhfaMHn37uzQ 提取碼:3kyr

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/223817.html

標籤:其他

上一篇:python爬取新筆趣閣小說

下一篇:Speaker Encoder復現: Transfer Learning from Speaker Verification to Multispeaker TTS

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more