Существует простой алгоритм O (n), основанный на том факте, что в дереве всегда есть несколько листьев, и если мы удалим лист, оставшийся граф все еще является деревом. Таким образом, мы можем удалить листья один за другим и обработать все дерево (все ребра) таким образом.
Вам нужно будет найти самый легкий путь для каждого узла.
Итак, давайте предположим, что вы обрабатываете некоторый лист, а узел n связан с узловым листом, и мы хотим быть уверены, что вы следите за любым путем, проходящим через край, который соединяет это n и лист. Давайте посмотрим на картину
направление здесь означает только направление от узлов, удалений раньше своих «родителей», узла, которые будут удалены позже, это может зависеть от порядка п, которые вы обрабатываете листья.
Если у нас есть кратчайший путь, проходящий через лист, и n, он может подключить любой «ребенок» к листу с каким-либо другим ребенком n или он может подключить любой «ребенок» листа к остальной части дерева.
В обоих случаях достаточно сохранить кратчайший путь от любого из уже обработанных узлов до текущего узла. Когда мы обрабатываем лист, мы берем легкий путь, основанный на листе, и добавляем вес соединения с ним и сравниваем его с самым коротким путем, уже сохраненным для n. Таким образом, мы неизбежно придем к сопоставлению двух кратчайших путей для n и сможете объединить их и иметь самый короткий путь для n, сохраненный при обработке всех «детей» из n.
Итак, вот псевдокод.
for each (node in graph)
{
node.shortest_path = 0; //zero length path from this node to this node
}
leaves = new list(all leaves in graph); //O(n) to find
int minWeight = 0; //any zero length path is minimum weight path currently found
//note that we a going to add new elements in list during the iteration
//and we will need to iterate through all of them including new added
//so in usual programming languages you will need to use for cycle
for each (leaf in leaves)
{
//we will have last node in tree with no connection
//because we will delete it on previous iteration
//and we don't need to process this node
//for this problem it is last node,
//but it may be not last if we have several trees instead of one
if (no point connected to leaf) continue;
n = only one node still connected to leaf
connection = connection between n and leaf
//check if we can make a short path which goes through n
//from one already processed "child" node to another
if (leaf.shortest_path +
connection.weight
+ n.shortest_path < minWeight )
{
minWeight = leaf.shortest_path+connection.weight+n.shortest_path;
}
//and we need to keep lightest path from any processed "child" to n
if (leaf.shortest_path + connection.weight < n.shortest_path)
{
n.shortest_path = leaf.shortest_path + connection.weight;
if(n.shortest_path < minWeight)
{
minWeight = n.shortest_path;
}
}
//delete connection and
connection.delete();
//if n is now leaf add it to leaf list
if (n is leaf)
{
leaves.Add(n);
}
}
Таким образом, в основном цикле мы обрабатывали каждый узел ровно один раз, чтобы у нас была сложность O (n). Если вам нужен ненулевой путь длины, но этот алгоритм не нашел его, это означает, что все ребра имеют положительный вес, а самый легкий путь без нулевой длины - самый легкий край.
Какой будет путь? корневой узел -> любой листовой узел? –
Уважаемый @RatulSharker, просто мы знаем, мы хотим найти простой путь с самым легким весом. длина пути представляет собой сумму веса ребер. –
В дереве, который является графиком? Простой путь - это путь, который не проходит через одну и ту же вершину дважды? Будет ли это путь нулевой длины или путь, состоящий из самого легкого края? Может быть, есть некоторые дополнительные условия? – Lurr