Trouver le diamètre du graphique par recherche de priorité de largeur (mémoire Python)

Je me suis enregistré avec Qiita, mais je ne l'ai pas tellement utilisé, alors je vais l'essayer.

Objectif de cet article

・ Mémo personnel ・ J'ai déjà cherché un article sur la recherche de priorité de largeur Python, mais je ne l'ai pas trouvé, alors j'aimerais le publier pour des débutants similaires. ・ Quelqu'un peut vous dire comment mieux écrire si vous écrivez ici

Conclusion

-Le diamètre d'un graphe qui est connecté et qui n'a pas de longueur de côté peut être obtenu par la recherche de priorité de largeur (BFS). -L'opération pour récupérer l'élément du haut de la liste est lente ・ Cependant, l'utilisation de deque l'améliorera un peu.

Problème à résoudre et politique de réponse

problème

ABC151 D - Maze Master

Résolvez ceci. (La question D d'ABC reçoit parfois une question graphique.) Veuillez vérifier l'énoncé du problème sur le lien.

Politique de réponse

Interprétez-le comme un problème de graphique. Le labyrinthe est représenté par un graphe connecté en connectant les sommets adjacents en haut, en bas, à gauche et à droite avec la masse en tant que sommet. Par conséquent, ce problème peut être considéré comme «le problème de trouver le diamètre d'un graphe qui est connecté et qui n'a pas de longueur de côté». Ici, le diamètre est la valeur maximale de la distance entre les sommets.

Qu'est-ce que la recherche de priorité de largeur (BFS)?

Pour plus de détails, consultez d'autres articles, mais la recherche de priorité de largeur est un algorithme permettant de trouver un emplacement accessible à partir d'un certain sommet (appelons-le start).

Cette fois, je vais appliquer cela ** Trouvez la distance maximale depuis le départ **. Tout d'abord, préparez une liste d'arêtes qui se connectent à chaque sommet, puis entrez la distance depuis le début dans la liste préparée (distance) conformément à l'organigramme suivant.

フロー1resize.png

Si vous remplacez la partie «depuis le début» écrite en rouge dans cet organigramme par «depuis la fin», elle devient une recherche prioritaire en profondeur (DFS). Cependant, le diamètre du graphique n'est pas calculé par DFS.

La recherche avec priorité à la largeur ne provoque pas de détour car elle se déplace immédiatement vers les sommets accessibles. Par conséquent, la distance la plus courte peut être obtenue. Bien sûr, à moins que les côtés aient de la longueur.

Enfin, faites cela pour tous les sommets du graphe et imprimez la plus grande des valeurs obtenues pour terminer.


H,W=[int(s) for s in input().split()]
maze=[input() for _ in range(H)]
 
edge=[set() for _ in range(H*W)]
n=0
numcount=0
for h in range(H):
  for w in range(W):
    if maze[h][w]=='#':
      numcount+=1
      n+=1
      continue
    if h>0 and maze[h-1][w]=='.':
      edge[n].add(n-W)
    if h<H-1 and maze[h+1][w]=='.':
      edge[n].add(n+W)
    if w>0 and maze[h][w-1]=='.':
      edge[n].add(n-1)
    if w<W-1 and maze[h][w+1]=='.':
      edge[n].add(n+1)
    n+=1

def dfs(start):
  reach=[start]
  distance=[-1 for _ in range(H*W)]
  distance[n]=0
  while reach:
    _from=reach.pop(0)
    for _to in edge[_from]:
      if not(_to in reach) and distance[_to]==-1:
        reach.append(_to)
        distance[_to]=distance[_from]+1
  return(max(distance))
 
n=0
ans=set()
for h in range(H):
  for w in range(W):
    if maze[h][w]=='.':
      ans.add(dfs(n))
    n+=1
print(max(ans))

Vous pouvez maintenant AC.

Atteindre le haut de la liste est lent

En gros, c'est bien, mais ... python est assez lent et deviendra rapidement TLE si vous ne faites pas attention. Il vaut mieux réduire au maximum les opérations chronophages. Par exemple, la récupération d'un élément du haut d'une liste est très lente.

import time
list_1=[i for i in range(100000)]
list_2=[i for i in range(100000)]

#Extraire les éléments du début
start_1=time.time()
while list_1:
  x=list_1.pop(0)
end_1=time.time()

#Extraire les éléments de la fin
start_2=time.time()
while list_2:
  x=list_2.pop(-1)
end_2=time.time()

print('Depuis le début:{}'.format(end_1-start_1))
 #=>Depuis le début: 1.4942412376403809
print('À partir de la fin:{}'.format(end_2-start_2))
 #=>À partir de la fin: 0.014818668365478516

Même si je fais la même opération, cela prend environ 100 fois plus de temps lorsque je retire l'élément depuis le début. C'était bien cette fois, mais je pense qu'il vaut mieux prendre des mesures lorsque de nombreuses opérations similaires se poursuivent.

utiliser deque

Lors de la récupération d'un élément du haut d'une liste, un type appelé deque est utile. Voir ici pour plus de détails. collections --- type de données de conteneur (documentation Python 3.7.3)

Grosso modo -Deque est rapide lors de l'extraction d'éléments depuis le début ou la fin d'un tableau ・ La liste est rapide lors de la sortie du centre Ça ressemble à ça.

import time
from collections import deque

list_1=[i for i in range(100000)]
deq=deque([i for i in range(100000)])

#Commencez par le début avec la liste
start_1=time.time()
while list_1:
  x=list_1.pop(0)
end_1=time.time()

#Commencez par le début avec deque
start_3=time.time()
while deq:
  x=deq.popleft()
end_3=time.time()

print('list:{}'.format(end_1-start_1))
 #=>list:1.4939298629760742
print('deque:{}'.format(end_3-start_3))
 #=>deque:0.009586334228515625

Cela s'est terminé très tôt. Le problème cette fois est que la longueur de la liste est d'environ 400, donc cela ne fait pas beaucoup de différence (plutôt lent), mais plus elle est longue, plus elle a de chances d'en bénéficier. La réponse en utilisant deque est la suivante.


from collections import deque
 
H,W=[int(s) for s in input().split()]
maze=[input() for _ in range(H)]
 
edge=[set() for _ in range(H*W)]
n=0
numcount=0
for h in range(H):
  for w in range(W):
    if maze[h][w]=='#':
      numcount+=1
      n+=1
      continue
    if h>0 and maze[h-1][w]=='.':
      edge[n].add(n-W)
    if h<H-1 and maze[h+1][w]=='.':
      edge[n].add(n+W)
    if w>0 and maze[h][w-1]=='.':
      edge[n].add(n-1)
    if w<W-1 and maze[h][w+1]=='.':
      edge[n].add(n+1)
    n+=1

def dfs(start):
  reach=deque([start])                               #Cette ligne change
  distance=[-1 for _ in range(H*W)]
  distance[n]=0
  while reach:
    _from=reach.popleft()                            #Cette ligne change
    for _to in edge[_from]:
      if not(_to in reach) and distance[_to]==-1:
        reach.append(_to)
        distance[_to]=distance[_from]+1
  return(max(distance))
 
n=0
ans=set()
for h in range(H):
  for w in range(W):
    if maze[h][w]=='.':
      ans.add(dfs(n))
    n+=1
print(max(ans))

Résumé

Cette fois, j'ai découvert BFS. Pour être honnête, je n'avais pas réalisé que le diamètre était calculé par BFS avant de résoudre ce problème. J'aimerais essayer de résoudre d'autres problèmes de graphes et les poster quand j'en ai le temps.

Recommended Posts

Trouver le diamètre du graphique par recherche de priorité de largeur (mémoire Python)
Trouvez le chemin critique de PERT en utilisant la recherche de priorité de largeur et la recherche de priorité de profondeur
[python] Vérifier la consommation de mémoire des variables
Pandas du débutant, par le débutant, pour le débutant [Python]
À la recherche du FizzBuzz le plus rapide en Python
Découvrez la fraction de la valeur saisie en python
Trouvez la solution de l'équation d'ordre n avec python
Rechercher par la valeur de l'instance dans la liste
[Calcul scientifique / technique par Python] Calcul numérique pour trouver la valeur de la dérivée (différentielle)
[Calcul scientifique / technique par Python] Solution analytique sympa pour résoudre des équations
Trouvez le maximum de Python
Exercice Python Recherche prioritaire sur 1 largeur
le zen de Python
Trouver la fonction de distribution cumulative par tri (version Python)
Connaissez l'emplacement du fichier de définition de classe Python.
J'ai essayé de trouver l'entropie de l'image avec python
[Python] BFS (recherche de priorité de largeur) ABC168D
Découvrez la largeur apparente d'une chaîne en python
Vers la retraite de Python2
Trouver des erreurs en Python
Avoir le graphique d'équation de la fonction linéaire dessiné en Python
Recherche de priorité de largeur / recherche bidirectionnelle (édition Python)
Python --Trouvez le nombre de groupes dans l'expression regex
Attacher au processus Python de la destination SSH et déboguer
Composants liés du graphique
[Python] Recherche de priorité de profondeur et recherche de priorité de largeur
À propos des fonctionnalités de Python
Google recherche la chaîne sur la dernière ligne du fichier en Python
Trouver les valeurs propres d'une vraie matrice symétrique en Python
Le pouvoir des pandas: Python
Trouvez la valeur maximale python (amélioré)
Python: Trouvez l'épaisseur de plaque requise pour la pression limite de flambage du tube exposé par la méthode Brent
[Python] Afficher uniquement les éléments de la liste côte à côte [Vertical, horizontal]
Comment vérifier la taille de la mémoire d'une variable en Python
[Python] Notification LINE des dernières informations à l'aide de la recherche automatique Twitter
Découvrez le changement mystérieux de la description du livre illustré Pokemon par Levenstein Distance
Lire la sortie standard d'un sous-processus ligne par ligne en Python
[Hikari-Python] Chapitre 07-02 Gestion des exceptions (exécution continue du programme par gestion des exceptions)
Comment vérifier la taille de la mémoire d'un dictionnaire en Python
Comment trouver l'adresse mémoire de la valeur de la trame de données Pandas
Trouvez le ratio de la superficie du lac Biwa par la méthode de Monte Carlo
[Python] Une fonction simple pour trouver les coordonnées du centre d'un cercle
Algorithme en Python (recherche de priorité de largeur, bfs)
Trouvez la définition de la valeur de errno
L'histoire de Python et l'histoire de NaN
[Python] Trouvez la deuxième plus petite valeur.
[Python] La pierre d'achoppement de l'importation
Extension du dictionnaire python par argument
Recherche de priorité de largeur (BPF) Peut-être compris (python)
Existence du point de vue de Python
Revue des bases de Python (FizzBuzz)
Comportement de python3 par le serveur de Sakura
À propos de la liste de base des bases de Python
Histoire d'approximation de puissance par Python