Вычислить достижимость элементов в списке кортежей

1

У меня есть список кортежей вроде этого.

a = [(1,2),(1,3),(1,4),(2,5),(6,5),(7,8)]

В этом списке 1 относится к 2, а затем 2 относится к 5 и 5 относится к 6, поэтому 1 относится к 6. Аналогично мне нужно найти отношения между другими элементами в кортежах. Мне нужна функция, которая принимает входные значения и выходы следующим образом:

input = (1,6) #output = True
input = (5,3) #output = True
input = (2,8) #output = False

У меня нет знаний о функциях itertools или map. Могут ли они использоваться для решения этих проблем? И ради любопытства и интереса, где я могу найти эти типы вопросов для решения и где эти типы проблем встречаются в реальных жизненных ситуациях?

  • 0
    Добавлен тег! Хорошо. Благодарю. Я буду искать в Интернете.
  • 0
    Возможный дубликат stackoverflow.com/questions/354330/… .
Показать ещё 8 комментариев
Теги:
python-3.x
reachability

2 ответа

6

Это можно легко сделать, рассматривая кортежи как ребра в графе. Затем вопрос сводится к проверке наличия пути между двумя узлами.

Для этого существует множество хороших библиотек, например, networkx

import networkx as nx

a = [(1,2),(1,3),(1,4),(2,5),(6,5),(7,8)]

G = nx.Graph(a)

nx.has_path(G, 1, 6)  # True
nx.has_path(G, 5, 3)  # True
nx.has_path(G, 2, 8)  # False
2

Этот ответ здесь красиво заявляет вашу проблему как проблема графа, где каждый раз, когда вам нужно запустить алгоритм, Вы должны проверить существование пути между вашими входными вершинами. Сложность времени для каждого запроса тогда зависит от размера, порядка, диаметра, степени лежащего в основе графика.

Однако, если вы собираетесь многократно запускать этот алгоритм с одним и тем же массивом a, возможно, стоит сделать некоторую предварительную обработку на входном графике, чтобы сначала найти связанные компоненты (Wikipedia: связанные компоненты). В этом случае вы можете получить постоянное время для каждого запроса. Вот код, который я предлагаю:

# NOTE : tested using python 3.6.1
# WARNING : no input sanitization

a = [(1,2),(1,3),(1,4),(2,5),(6,5),(7,8)]
n = 8 # order of the underlying graph

# prepare graph as lists of neighbors for every vertex, i.e. adjacency lists (extra unused vertex '0', just to match the value range of the problem)
graph = [[] for i in range(n+1)]
for edge in a:
  graph[edge[0]].append(edge[1])
  graph[edge[1]].append(edge[0])
print( "graph : " + str(graph) )

# list of unprocessed vertices : contains all of them at the beginning
unprocessed_vertices = {i for i in range(1,n+1)}

# subroutine to discover the connected component of a vertex
def build_component():
  component = [] # current connected component
  curr_vertices = {unprocessed_vertices.pop()} # locally unprocessed vertices, initialize with one of the globally unprocessed vertices
  while len(curr_vertices) > 0:
    curr_vertex = curr_vertices.pop() # vertex to be processed
    # add unprocessed neighbours of current vertex to the set of vertices to process
    for neighbour in graph[curr_vertex]:
      if neighbour in unprocessed_vertices:
        curr_vertices.add(neighbour)
        unprocessed_vertices.remove(neighbour)
    component.append(curr_vertex)
  return component

# main algorithm : graph traversal on multiple connected components
components = []
while len(unprocessed_vertices) > 0:
  components.append( build_component() )
print( "components : " + str(components) )

# assign a number to each component
component_numbers = [None] * (n+1)
curr_number = 1
for comp in components:
  for vertex in comp:
    component_numbers[vertex] = curr_number
  curr_number += 1
print( "component_numbers : " + str(component_numbers) )

# main functionality
def is_connected( pair ):
  return component_numbers[pair[0]] == component_numbers[pair[1]]

# run main functionnality on inputs : every call is executed in constant time now, regardless of the size of the graph
print( is_connected( (1,6) ) )
print( is_connected( (5,3) ) )
print( is_connected( (2,8) ) )

Я действительно не знаю о наиболее вероятных ситуациях, когда эта проблема может возникнуть, но я полагаю, что приложение может иметь некоторые задачи кластеризации, или, может быть, если вы хотите знать, можно ли переходить из одного места в другое. Если ребра графа представляют зависимости между модулями, эта проблема скажет вам, зависят ли две части друг от друга, поэтому, возможно, некоторые потенциальные приложения при компиляции или управлении крупными проектами. Основная проблема - проблема "Связанный компонент", которая входит в число проблем, для которых мы знаем полиномиальные алгоритмы.

Как правило, очень полезно моделировать такие проблемы с графиками, поскольку эти объекты имеют очень простую структуру, и большую часть времени мы можем свести исходную проблему к хорошо известной проблеме на графиках.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню