ОБНОВЛЕНИЕ: У ОП теперь было несколько раундов разъяснений, и теперь это другая проблема.Я оставлю это здесь для документирования моих идей для первой версии проблемы (точнее, моего понимания).Я попробую новый ответ для текущей версии проблемы. Конец ОБНОВЛЕНИЯ
Жаль, что ФП не прояснил некоторые открытые вопросы.Я предполагаю следующее:
- Веса +/- 1.
- n - количество вершин
Первое предположение - нетпотеря общности, очевидно, но это оказывает большое влияние на значение n (посредством второго предположения).Без первого предположения даже крошечный (фиксированный) граф может иметь произвольные длинные решения, варьируя веса без ограничений.
Алгоритм, который я предлагаю, довольно прост и похож на известные алгоритмы графов.Я не эксперт по графику, поэтому я могу использовать неправильные слова в некоторых местах.Не стесняйтесь поправлять меня.
- Для исходной вершины запомните стоимость 0. Добавьте (source, 0) в список задач.
- Выдвиньте элемент из списка задач.Следуйте всем исходящим ребрам вершины, вычисляя новую стоимость c, чтобы достичь новой вершины v. Если новая стоимость действительна (c> = 0 и c <= n ^ 2 </strong>, см. Ниже), а незапоминается для v, добавьте к запомненным значениям стоимости v и добавьте (v, c) в свой список задач.
- Если список задач не пуст, перейдите к шагу 2(Или прервитесь рано, если пункт назначения может быть достигнут со стоимостью 0).
Понятно, что каждый «шаг», который не является непосредственным тупиком, создает новую комбинацию (вершина, стоимость).Будет сохранено не более n * n ^ 2 = n ^ 3 этих комбинаций, и, таким образом, в определенном смысле этот алгоритм является O (n ^ 3).
Теперь, почемуэто найти оптимальный путь? У меня нет реальных доказательств, но я думаю, что следующие идеи обосновывают, почему я думаю, что этого достаточно, и может быть возможно, что они могут быть превращены в реальные доказательства.
Я думаю, что ясно, что единственное, что мы должны показать, это то, что условие c <= n ^ 2 является достаточным.</p>
Во-первых, отметим, что любая (достижимая) вершина может быть достигнута со стоимостью менее n.
Пусть (v, c) будет частью оптимального пути и c> n ^ 2.Поскольку c> n, должен быть некоторый цикл на пути до достижения (v, c), где стоимость цикла равна 0 м2> -n.
Кроме того, пусть v будет достижимым из источника со стоимостью 0 <= c1 <n по пути, который касается первого цикла, упомянутого выше,и пусть назначение будет достижимо из v со стоимостью 0 <= c2 <n, путем, который касается другого цикла, упомянутого выше. </p>
Тогда мы можем построить пути от источника до v с ценами c1, c1 + m1, c1 + 2 * m1, ... и пути от v до места назначения с затратами c2, c2 + m2, c2 + 2 * m2, ....Выберите 0 <= a <= m2 и 0 <= b <= m1 так, чтобы c1 + c2 + a * m1 + b * m2 был минимальным и, следовательно, стоил оптимальный путь.На этом оптимальном пути v будет иметь стоимость c1 + a * m1 <n ^ 2. </p>
Если gcd для m1 и m2 равен 1, тогда стоимость будет равна 0. Если gcd равен> 1,тогда можно было бы выбрать другие циклы, так что gcd становится равным 1. Если это невозможно, это также невозможно для оптимального решения, и для оптимального решения будут положительные затраты.
(Да, я могу видеть несколько проблем с этой попыткой доказательства. Возможно, необходимо взять gcd нескольких положительных или отрицательных затрат цикла и т. Д. Я бы очень заинтересовался контрпримером.)
Вотнекоторый (Python) код:
def f(vertices, edges, source, dest):
# vertices: unique hashable objects
# edges: mapping (u, v) -> cost; u, v in vertices, cost in {-1, 1}
#vertex_costs stores the possible costs for each vertex
vertex_costs = dict((v, set()) for v in vertices)
vertex_costs[source].add(0) # source can be reached with cost 0
#vertex_costs_from stores for each the possible costs for each vertex the previous vertex
vertex_costs_from = dict()
# vertex_gotos is a convenience structure mapping a vertex to all ends of outgoing edges and their cost
vertex_gotos = dict((v, []) for v in vertices)
for (u, v), c in edges.items():
vertex_gotos[u].append((v, c))
max_c = len(vertices) ** 2 # the crucial number: maximal cost that's possible for an optimal path
todo = [(source, 0)] # which vertices to look at
while todo:
u, c0 = todo.pop(0)
for v, c1 in vertex_gotos[u]:
c = c0 + c1
if 0 <= c <= max_c and c not in vertex_costs[v]:
vertex_costs[v].add(c)
vertex_costs_from[v, c] = u
todo.append((v, c))
if not vertex_costs[dest]: # destination not reachable
return None # or raise some Exception
cost = min(vertex_costs[dest])
path = [(dest, cost)] # build in reverse order
v, c = dest, cost
while (v, c) != (source, 0):
u = vertex_costs_from[v, c]
c -= edges[u, v]
v = u
path.append((v, c))
return path[::-1] # return the reversed path
И вывод для некоторых графиков (ребра и их вес / путь / стоимость в каждой точке пути; извините, нет хороших изображений):
AB+ BC+ CD+ DA+ AX+ XY+ YH+ HI- IJ- JK- KL- LM- MH-
A B C D A X Y H I J K L M H
0 1 2 3 4 5 6 7 6 5 4 3 2 1
AB+ BC+ CD+ DE+ EF+ FG+ GA+ AX+ XY+ YH+ HI- IJ- JK- KL- LM- MH-
A B C D E F G A B C D E F G A B C D E F G A X Y H I J K L M H I J K L M H I J K L M H I J K L M H
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
AB+ BC+ CD+ DE+ EF+ FG+ GA+ AX+ XY+ YH+ HI- IJ- JK- KL- LM- MN- NH-
A X Y H
0 1 2 3
AB+ BC+ CD+ DE+ EF+ FG+ GA+ AX+ XY+ YH+ HI- IJ- JK- KL- LM- MN- NO- OP- PH-
A B C D E F G A B C D E F G A B C D E F G A B C D E F G A B C D E F G A B C D E F G A X Y H I J K L M N O P H I J K L M N O P H I J K L M N O P H I J K L M N O P H I J K L M N O P H
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Вот код для вывода:
def find_path(edges, source, path):
from itertools import chain
print(edges)
edges = dict(((u, v), 1 if c == "+" else -1) for u, v, c in edges.split())
vertices = set(chain(*edges))
path = f(vertices, edges, source, dest)
path_v, path_c = zip(*path)
print(" ".join("%2s" % v for v in path_v))
print(" ".join("%2d" % c for c in path_c))
source, dest = "AH"
edges = "AB+ BC+ CD+ DA+ AX+ XY+ YH+ HI- IJ- JK- KL- LM- MH-"
# uv+ means edge from u to v exists and has cost 1, uv- = cost -1
find_path(edges, source, path)
edges = "AB+ BC+ CD+ DE+ EF+ FG+ GA+ AX+ XY+ YH+ HI- IJ- JK- KL- LM- MH-"
find_path(edges, source, path)
edges = "AB+ BC+ CD+ DE+ EF+ FG+ GA+ AX+ XY+ YH+ HI- IJ- JK- KL- LM- MN- NH-"
find_path(edges, source, path)
edges = "AB+ BC+ CD+ DE+ EF+ FG+ GA+ AX+ XY+ YH+ HI- IJ- JK- KL- LM- MN- NO- OP- PH-"
find_path(edges, source, path)