Найдите путь, проходящий через определенные узлы в графике

#python #graph

Вопрос:

Вопрос в следующем : учитывая ограничение и график, могу ли я найти эффективный способ проверить, могу ли я его удовлетворить ?

У меня есть графики/деревья, подобные тезисам : примеры деревьев и ограничений

У меня есть ограничения, специфические для каждого графика, такие как «UUB ?» для A). Ограничение спрашивает, есть ли в графике путь, проходящий через каждую из букв, указанных в ограничении.

Для ограничения «UUB ?» нам нужен путь, проходящий по крайней мере через два U и один B. Для первого графика «UUB ?» возможно с путем U-gt;B-gt;gt;U. «RBB ?» невозможно, потому что один из B находится на том же слое, что и R, и вы не можете иметь оба одновременно. Я не нашел никакого эффективного метода проверки того, может ли быть выполнено ограничение..

Точность ограничения : Ограничение не может содержать больше букв, чем количество слоев. Порядок ограничения не имеет значения (UBB совпадает с BUB и BBU).

Точность графика : Эти графики ориентированы, и каждый слой (столбец) полностью связан со следующим. Они могут иметь максимум 5 слоев (столбцов) и 5 строк (U,B,R,G,W).

Они могут быть представлены в виде векторов (соответственно):

A)
U 1 0 1
B 1 1 0
R 1 0 0

Б)
U 1 0 1 0
B 1 1 0 1
R 1 0 1 0
G 1 1 0 0

C)
U 1 0 1 0 0
B 1 1 0 1 0
R 1 0 1 0 0
G 1 1 0 0 0
W 0 0 1 0 1

Точность алгоритма : Эта проверка будет происходить на каждом шаге моделирования Монте-Карло из миллионов шагов, она должна быть как можно быстрее (это означает, что я не могу извлечь все пути и проверить, включают ли они нужные узлы..)

Я нашел простые способы проверить, не может ли график удовлетворять ограничению, но противоположное кажется сложным (по крайней мере, для меня я далек от эксперта по графам, но я могу понять ключевые понятия).

Спасибо вам за чтение и за вашу помощь !

Ответ №1:

Вы можете использовать рекурсивную функцию генератора, выстраивая возможные пути при каждом вызове, сверяя частоты букв выполняемой комбинации с частотами возможных путей:

 from collections import Counter def check_paths(d, p, c=[], f={}):  if not d and any(all(j in i and i[j] == k for j, k in f.items()) for i in p):  yield c #produce a path if all the layers have been examined and all the letter frequencies from the path match a possible path  elif d:  for x in d[0]:  _c = Counter(c [x])  #check if the current path, with the addition of a new letter, is below or equals the frequency threshold of any of the target paths  if any(all(j in i and i[j] gt;= k for j, k in _c.items()) for i in p):  yield from check_paths(d[1:], p, c=c [x], f=_c)  

 l = ['U', 'B', 'R', 'G', 'W'] def path_exists(m, p):  v = [[j for j, k in zip(l, i) if k] for i in zip(*m)]  return next(check_paths(v, [Counter(i) for i in p]), None) is not None  print(path_exists([[1, 0, 1], [1, 1, 0], [1, 0, 0]], ['UUB', 'RBB', 'UBR'])) print(path_exists([[1, 0, 1, 0], [1, 1, 0, 1], [1, 0, 1, 0], [1, 1, 0, 0]], ['UBBB', 'RGRR', 'UBRG'])) print(path_exists([[1, 0, 1, 0, 0], [1, 1, 0, 1, 0], [1, 0, 1, 0, 0], [1, 1, 0, 0, 0], [0, 0, 1, 0, 1]], ['UBRGW', 'RGRGG', 'WWRUB']))  

Выход:

 True True True  

Комментарии:

1. Он работает, но я не уверен, что понимаю код, можете ли вы добавить некоторые комментарии к нему? Я немного растерян …

2. @Jacques Пожалуйста, посмотрите мою недавнюю правку.

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