@Este artículo proviene del número público: csdn2299, me gusta prestar atención a la escuela de programadores de números públicos ¿Cuál es el
primer algoritmo de profundidad (algoritmo DFS)?
El algoritmo para encontrar la ruta entre el nodo inicial y el nodo objetivo a menudo se usa para buscar la ruta para escapar del laberinto. La idea principal es que a partir de la entrada, se buscan en orden las posibles coordenadas de los nodos circundantes, pero no pasarán por el mismo nodo repetidamente y no podrán pasar por los nodos de obstáculos. Si va a un nodo y descubre que no hay forma de hacerlo, volverá al nodo anterior y elegirá otra ruta. Hasta que se encuentre la salida, o no haya forma de volver al punto de partida, el juego termina. Por supuesto, el algoritmo de profundidad primero dejará de buscar siempre que encuentre una ruta de trabajo; es decir, mientras haya un camino por recorrer, el algoritmo de profundidad primero no volverá al paso anterior.
Si todavía está confundido en el mundo de la programación, puede unirse a nuestro botón de aprendizaje de Python qun: 784758214 para ver cómo aprendieron los predecesores. Intercambio de experiencia! Soy un ingeniero senior de desarrollo de python, desde scripts básicos de python hasta desarrollo web, rastreadores, django, minería de datos, etc., desde cero hasta proyectar información de combate real. ¡A cada pequeño amigo de Python! Comparta algunos métodos de aprendizaje y pequeños detalles que requieren atención, haga clic para unirse a nuestro lugar de reunión de estudiantes de Python
La siguiente figura es una ruta buscada utilizando el algoritmo DFS:
Resumir:
Comenzando desde el punto de partida, consulte los nodos que pueden pasar por el siguiente paso, e inserte estos posibles nodos en la pila, y los nodos que ya han pasado no volverán a intentarlo. Una vez completada la consulta, elimine un nodo de la pila y consulte si hay un nodo de trabajo alrededor del nodo. Si no hay un nodo posible, continúe tomando un nodo de la pila. Repita la operación anterior hasta que el nodo actual sea el punto final o no haya más nodo en la pila.
Definir los datos:
Nodo de inicio y nodo de destino
Pila de nodos de almacenamiento
Definir funciones auxiliares
Obtenga la función del siguiente nodo: función sucesora para
determinar si es el punto final: test_goal
Primero, definamos la estructura de datos de la pila. La pila es una estructura de datos de último en entrar, primero en salir.
Debido a que la búsqueda de amplitud primero usará la cola más tarde, y el algoritmo A * usará la cola de prioridad, hemos definido una clase base abstracta para su uso posterior. deque es una cola de doble extremo, similar a la operación de lista de tipos incorporada, pero la complejidad temporal de las operaciones de inserción y eliminación de cabeza y cola son O (1).
# utils.py
from abc import abstractmethod, ABC
from collections import deque
class Base(ABC):
def __init__(self):
self._container = deque()
@abstractmethod
def push(self, value):
"""push item"""
@abstractmethod
def pop(self):
"""pop item"""
def __len__(self):
return len(self._container)
def __repr__(self):
return f'{type(self).__name__}({list(self._container)})'
class Stack(Base):
def push(self, value):
self._container.append(value)
def pop(self):
return self._container.pop()
A continuación, definamos la función dfs. Entre ellos, inicial es el nodo inicial, s es la pila, y marcado se usa para registrar los nodos que pasan. La función sucesora se usa para buscar el siguiente nodo posible, y la función test_goal se usa para determinar si el nodo es el nodo objetivo. children es una lista de posibles nodos, atraviesa estos nodos, empuja los nodos que no han viajado a la pila y haz un registro.
# find_path.py
from utils import Stack
def dfs(initial, _next = successor, _test = test_goal):
s: Stack = Stack()
marked = {initial}
s.push(initial)
while s:
parent: state = s.pop()
if _test(parent):
return parent
children = _next(parent)
for child in children:
if child not in marked:
marked.add(child)
s.push(child)
A continuación, usamos el algoritmo DFS para encontrar la ruta del laberinto y demostrar visualmente la ruta del laberinto buscado.
Primero use una enumeración para indicar el color de la ruta, VACÍO es el nodo normal, BLOQUEADO es el nodo de obstáculo, INICIO es la entrada del laberinto, FIN es la salida del laberinto y RUTA es la ruta de búsqueda.
from enum import IntEnum
class Cell(IntEnum):
EMPTY = 255
BLOCKED = 0
START = 100
END = 200
PATH = 150
A continuación, definamos el laberinto. Primero, usamos Namedtuple para definir las coordenadas de cada nodo del laberinto:
class MazeLocation(NamedTuple):
row: int
col: int
En primer lugar, para facilitar la determinación de la relación entre nodos, definimos una clase interna _Nodo en la clase Maze para registrar el estado del nodo y el nodo padre del nodo.
class _Node:
def __init__(self, state, parent):
self.state = state
self.parent = parent
Luego inicialice, determine las coordenadas de la entrada y la salida, use la función np.random.choice para generar aleatoriamente el laberinto y marque la entrada y la salida.
def __init__(self, rows: int = 10, cols: int = 10,
sparse: float = 0.2, seed: int = 365,
start: MazeLocation = MazeLocation(0, 0),
end: MazeLocation = MazeLocation(9, 9), *,
grid: Optional[np.array] = None) -> None:
np.random.seed(seed)
self._start: MazeLocation = start
self._end: MazeLocation = end
self._grid: np.array = np.random.choice([Cell.BLOCKED, Cell.EMPTY],
(rows, cols), p=[sparse, 1 - sparse])
self._grid[start] = Cell.START
self._grid[end] = Cell.END
El segundo es el método test_goal, siempre que las coordenadas del nodo sean relativas al nodo objetivo.
def _test_goal(self, m1: MazeLocation) -> bool:
return m1 == self._end
Luego está el método sucesor: siempre que los nodos en las direcciones arriba, abajo, izquierda y derecha no sean obstáculos y estén dentro del límite, se tendrán en cuenta y se agregarán a la lista.
List[MazeLocation]:
location: List[MazeLocation] = []
row, col = self._grid.shape
if m1.row + 1 < row and self._grid[m1.row + 1, m1.col] != Cell.BLOCKED:
location.append(MazeLocation(m1.row + 1, m1.col))
if m1.row - 1 >= 0 and self._grid[m1.row - 1, m1.col] != Cell.BLOCKED:
location.append(MazeLocation(m1.row - 1, m1.col))
if m1.col + 1 < col and self._grid[m1.row, m1.col + 1] != Cell.BLOCKED:
location.append(MazeLocation(m1.row, m1.col + 1))
if m1.col - 1 >= 0 and self._grid[m1.row, m1.col - 1] != Cell.BLOCKED:
location.append(MazeLocation(m1.row, m1.col - 1))
return location
La ruta de visualización, la pausa es el intervalo de visualización de la imagen y el trazado es la bandera de dibujo. Comenzando desde el nodo objetivo, atraviese el nodo padre de cada nodo hasta que llegue al nodo inicial y dibuje un mapa de ruta.
None:
if pause <= 0:
raise ValueError('pause must be more than 0')
path: Maze._Node = self._search()
if path is None:
print('没有找到路径')
return
path = path.parent
while path.parent is not None:
self._grid[path.state] = Cell.PATH
if plot:
self._draw(pause)
path = path.parent
print('Path Done')
Para utilizar el algoritmo DFS, definimos la clase DepthFirstSearch, heredando la clase laberinto. La clase DepthFirstSearch reescribe el método _search de la clase base, que es casi lo mismo que la definición de la función dfs que definimos anteriormente.
class DepthFirstSearch(Maze):
def _search(self):
stack: Stack = Stack()
initial: DepthFirstSearch._Node = self._Node(self._start, None)
marked: Set[MazeLocation] = {initial.state}
stack.push(initial)
while stack:
parent: DepthFirstSearch._Node = stack.pop()
state: MazeLocation = parent.state
if self._test_goal(state):
return parent
children: List[MazeLocation] = self._success(state)
for child in children:
if child not in marked:
marked.add(child)
stack.push(self._Node(child, parent))
class DepthFirstSearch(Maze):
def _search(self):
stack: Stack = Stack()
initial: DepthFirstSearch._Node = self._Node(self._start, None)
marked: Set[MazeLocation] = {initial.state}
stack.push(initial)
while stack:
parent: DepthFirstSearch._Node = stack.pop()
state: MazeLocation = parent.state
if self._test_goal(state):
return parent
children: List[MazeLocation] = self._success(state)
for child in children:
if child not in marked:
marked.add(child)
stack.push(self._Node(child, parent))
Muchas gracias por leer
. Cuando decidí estudiar Python en la universidad, descubrí que me comía una mala base informática. No tenía una calificación académica. Esto
no es nada que hacer. Solo puedo compensarlo, así que comencé mi propio contraataque fuera de la codificación. El camino, continúe aprendiendo los conocimientos básicos de Python, el estudio en profundidad de los conceptos básicos de la computadora, resuelto, si no está dispuesto a ser mediocre, ¡únase a mí en la codificación y continúe creciendo!
De hecho, no solo hay tecnología aquí, sino también cosas más allá de esas tecnologías. Por ejemplo, cómo ser un programador exquisito, en lugar de "seda de gallo", el programador en sí es una existencia noble, ¿no? [Haz clic para unirte] ¡ Quieres ser tú mismo, quieres ser una persona noble, vamos!