




import functools




def 					lowerCamelCase__       (						A__       :					str  ,			A__       :					str	):





       '''simple docstring'''



       __lowerCamelCase   =						len(A__	)
       __lowerCamelCase   =						len(A__	)

       @functools.cache
       def min_distance(A__       :					int  ,			A__       :					int	) -> int:
              # if first word index is overflow - delete all from the second word
              if indexa >= len_worda:
                     return len_worda - indexa
              # if second word index is overflow - delete all from the first word
              if indexa >= len_worda:
                     return len_worda - indexa
              __lowerCamelCase   =						int(worda[indexa] != worda[indexa]	)  # current letters not identical
              return min(
                  1 + min_distance(indexa + 1  ,			A__	)  ,			1 + min_distance(A__  ,			indexa + 1	)  ,			diff + min_distance(indexa + 1  ,			indexa + 1	)  ,			)

       return min_distance(0  ,			0	)


if __name__ == "__main__":
       import doctest

       doctest.testmod()









"""simple docstring"""





from __future__ import annotations

from typing import Generic, TypeVar

_SCREAMING_SNAKE_CASE					:				Optional[Any]					    =						TypeVar('''T''')






class      a						(					Generic[T]		):






    def __init__(       self     :							List[str]       ,						__SCREAMING_SNAKE_CASE     :							T					)     ->		None:
      lowerCamelCase_         =						data
      lowerCamelCase_         =						self
      lowerCamelCase_         =						0






class      a						(					Generic[T]		):






    def __init__(       self     :							Any					)     ->		None:
      # map from node name to the node object
      lowerCamelCase_         =						{}






    def    UpperCamelCase       (       self     :							List[str]       ,						__SCREAMING_SNAKE_CASE     :							T					)     ->		None:
      # create a new set with x as its member
      lowerCamelCase_         =						DisjointSetTreeNode(__SCREAMING_SNAKE_CASE					)






    def    UpperCamelCase       (       self     :							Optional[int]       ,						__SCREAMING_SNAKE_CASE     :							T					)     ->		DisjointSetTreeNode[T]:
      # find the set x belongs to (with path-compression)
      lowerCamelCase_         =						self.map[data]
      if elem_ref != elem_ref.parent:
        lowerCamelCase_         =						self.find_set(elem_ref.parent.data					)
      return elem_ref.parent






    def    UpperCamelCase       (       self     :							str       ,						__SCREAMING_SNAKE_CASE     :							DisjointSetTreeNode[T]       ,						__SCREAMING_SNAKE_CASE     :							DisjointSetTreeNode[T]					)     ->		None:
      # helper function for union operation
      if nodea.rank > nodea.rank:
        lowerCamelCase_         =						nodea
      else:
        lowerCamelCase_         =						nodea
        if nodea.rank == nodea.rank:
          nodea.rank += 1






    def    UpperCamelCase       (       self     :							List[str]       ,						__SCREAMING_SNAKE_CASE     :							T       ,						__SCREAMING_SNAKE_CASE     :							T					)     ->		None:
      # merge 2 disjoint sets
      self.link(self.find_set(__SCREAMING_SNAKE_CASE					)       ,						self.find_set(__SCREAMING_SNAKE_CASE					)					)






class      a						(					Generic[T]		):






    def __init__(       self     :							Optional[int]					)     ->		None:
      # connections: map from the node to the neighbouring nodes (with weights)
      lowerCamelCase_         =						{}






    def    UpperCamelCase       (       self     :							Optional[int]       ,						__SCREAMING_SNAKE_CASE     :							T					)     ->		None:
      # add a node ONLY if its not present in the graph
      if node not in self.connections:
        lowerCamelCase_         =						{}






    def    UpperCamelCase       (       self     :							Tuple       ,						__SCREAMING_SNAKE_CASE     :							T       ,						__SCREAMING_SNAKE_CASE     :							T       ,						__SCREAMING_SNAKE_CASE     :							int					)     ->		None:
      # add an edge with the given weight
      self.add_node(__SCREAMING_SNAKE_CASE					)
      self.add_node(__SCREAMING_SNAKE_CASE					)
      lowerCamelCase_         =						weight
      lowerCamelCase_         =						weight






    def    UpperCamelCase       (       self     :							List[Any]					)     ->		GraphUndirectedWeighted[T]:
      lowerCamelCase_         =						[]
      lowerCamelCase_         =						set()
      for start in self.connections:
        for end in self.connections[start]:
          if (start, end) not in seen:
            seen.add((end, start)					)
            edges.append((start, end, self.connections[start][end])					)
      edges.sort(key=lambda __SCREAMING_SNAKE_CASE					: x[2]					)

      # creating the disjoint set
      lowerCamelCase_         =						DisjointSetTree[T]()
      for node in self.connections:
        disjoint_set.make_set(__SCREAMING_SNAKE_CASE					)

      # MST generation
      lowerCamelCase_         =						0
      lowerCamelCase_         =						0
      lowerCamelCase_         =						GraphUndirectedWeighted[T]()
      while num_edges < len(self.connections					) - 1:
        lowerCamelCase_     ,	lowerCamelCase_     ,	lowerCamelCase_         =						edges[index]
        index += 1
        lowerCamelCase_         =						disjoint_set.find_set(__SCREAMING_SNAKE_CASE					)
        lowerCamelCase_         =						disjoint_set.find_set(__SCREAMING_SNAKE_CASE					)
        if parent_u != parent_v:
          num_edges += 1
          graph.add_edge(__SCREAMING_SNAKE_CASE       ,						__SCREAMING_SNAKE_CASE       ,						__SCREAMING_SNAKE_CASE					)
          disjoint_set.union(__SCREAMING_SNAKE_CASE       ,						__SCREAMING_SNAKE_CASE					)
      return graph




