Рубрики

Самый длинный путь в направленном ациклическом графе

Учитывая Взвешенное D irected Циклического G Рафа (DAG) и источник вершины с в нем, найти самые длинные расстояния от секунд до всех других вершин в данном графе.

Задача с самым длинным путем для общего графа не так проста, как задача с самым коротким путем, потому что задача с самым длинным путем не имеет оптимального свойства субструктуры . На самом деле, проблема Longest Path является NP-Hard для общего графа . Однако задача с самым длинным путем имеет линейное решение по времени для направленных ациклических графов. Идея аналогична линейному решению времени для кратчайшего пути в ориентированном ациклическом графе. Используем топологическую сортировку .

Мы инициализируем расстояния до всех вершин как минус бесконечность и расстояние до источника как 0, затем мы находим топологическую сортировку графа. Топологическая сортировка графа представляет линейное упорядочение графа (см. Ниже, рисунок (b) является линейным представлением фигуры (a)). Получив топологический порядок (или линейное представление), мы по очереди обрабатываем все вершины в топологическом порядке. Для каждой обрабатываемой вершины мы обновляем расстояния ее смежных, используя расстояние текущей вершины.

На следующем рисунке показан пошаговый процесс поиска самых длинных путей.

Ниже приводится полный алгоритм нахождения самых длинных расстояний.
1) Инициализируйте dist [] = {NINF, NINF,….} И dist [s] = 0, где s — исходная вершина. Здесь NINF означает отрицательное бесконечное.
2) Создайте топологический порядок всех вершин.
3) Выполните следующие действия для каждой вершины u в топологическом порядке.
………. Делайте следующее для каждой смежной вершины v из вас
……………… if (dist [v] <dist [u] + вес (u, v))
……………………… dist [v] = dist [u] + вес (u, v)

Следующее — реализация C ++ вышеупомянутого алгоритма.

// Программа на C ++ для поиска длинных расстояний от одного источника
// в DAG
#include <iostream>
#include <limits.h>
#include <list>
#include <stack>
#define NINF INT_MIN

using namespace std;

  
// График представлен с использованием списка смежности. каждый
// узел списка смежности содержит номер вершины
// вершина, с которой соединяется ребро. Это также
// содержит вес ребра

class AdjListNode { 

    int v; 

    int weight; 

    

public

    AdjListNode(int _v, int _w) 

    

        v = _v; 

        weight = _w; 

    

    int getV() { return v; } 

    int getWeight() { return weight; } 

}; 

    
// Класс для представления графа с использованием списка смежности
// представление

class Graph { 

    int V; // Количество вершин

    

    // Указатель на массив, содержащий списки смежности

    list<AdjListNode>* adj; 

    

    // Функция, используемая longestPath

    void topologicalSortUtil(int v, bool visited[], 

                             stack<int>& Stack); 

    

public

    Graph(int V); // Конструктор

    ~Graph(); // Деструктор

  

    // функция для добавления ребра на график

    void addEdge(int u, int v, int weight); 

    

    // Находит самые длинные расстояния от заданной исходной вершины

    void longestPath(int s); 

}; 

    

Graph::Graph(int V) // Конструктор

    this->V = V; 

    adj = new list<AdjListNode>[V]; 

  

Graph::~Graph() // Деструктор

    delete [] adj; 

  

  

void Graph::addEdge(int u, int v, int weight) 

    AdjListNode node(v, weight); 

    adj[u].push_back(node); // Добавить v в список u

    
// Рекурсивная функция, используемая longestPath. См. ниже
// ссылка для деталей
// https: // www.geeksforgeeks.org/topological-sorting/

void Graph::topologicalSortUtil(int v, bool visited[], 

                                stack<int>& Stack) 

    // Пометить текущий узел как посещенный

    visited[v] = true

    

    // Повторение для всех вершин, смежных с этой вершиной

    list<AdjListNode>::iterator i; 

    for (i = adj[v].begin(); i != adj[v].end(); ++i) { 

        AdjListNode node = *i; 

        if (!visited[node.getV()]) 

            topologicalSortUtil(node.getV(), visited, Stack); 

    

    

    // Вставляем текущую вершину в стек, который хранит топологию

    // Сортировать

    Stack.push(v); 

    
// Функция для нахождения наибольшего расстояния от заданной вершины.
// Он использует рекурсивную topologicalSortUtil () для получения топологической
// сортировка.

void Graph::longestPath(int s) 

    stack<int> Stack; 

    int dist[V]; 

    

    // Пометить все вершины как не посещенные

    bool* visited = new bool[V]; 

    for (int i = 0; i < V; i++) 

        visited[i] = false

    

    // Вызываем рекурсивную вспомогательную функцию для хранения топологии

    // Сортировка, начиная со всех вершин по одной

    for (int i = 0; i < V; i++) 

        if (visited[i] == false

            topologicalSortUtil(i, visited, Stack); 

    

    // Инициализировать расстояния до всех вершин как бесконечные и

    // расстояние до источника как 0

    for (int i = 0; i < V; i++) 

        dist[i] = NINF; 

    dist[s] = 0; 

    

    // Обработка вершин в топологическом порядке

    while (Stack.empty() == false) { 

        // Получить следующую вершину из топологического порядка

        int u = Stack.top(); 

        Stack.pop(); 

    

        // Обновляем расстояния всех смежных вершин

        list<AdjListNode>::iterator i; 

        if (dist[u] != NINF) { 

            for (i = adj[u].begin(); i != adj[u].end(); ++i) 

                if (dist[i->getV()] < dist[u] + i->getWeight()) 

                    dist[i->getV()] = dist[u] + i->getWeight(); 

        

    

    

    // Распечатать рассчитанные самые длинные расстояния

    for (int i = 0; i < V; i++) 

        (dist[i] == NINF) ? cout << "INF " : cout << dist[i] << " ";

      

    delete [] visited;

    
// Программа драйвера для проверки вышеуказанных функций

int main() 

    // Создать график, приведенный на диаграмме выше.

    // Здесь номера вершин 0, 1, 2, 3, 4, 5 с

    // следующие отображения:

    // 0 = r, 1 = s, 2 = t, 3 = x, 4 = y, 5 = z

    Graph g(6); 

    g.addEdge(0, 1, 5); 

    g.addEdge(0, 2, 3); 

    g.addEdge(1, 3, 6); 

    g.addEdge(1, 2, 2); 

    g.addEdge(2, 4, 4); 

    g.addEdge(2, 5, 2); 

    g.addEdge(2, 3, 7); 

    g.addEdge(3, 5, 1); 

    g.addEdge(3, 4, -1); 

    g.addEdge(4, 5, -2); 

    

    int s = 1; 

    cout << "Following are longest distances from "

            "source vertex "

         << s << " \n"

    g.longestPath(s); 

    

    return 0; 

}

Выход:

Following are longest distances from source vertex 1
INF 0 2 9 8 10

Сложность времени: временная сложность топологической сортировки O (V + E). После нахождения топологического порядка алгоритм обрабатывает все вершины и для каждой вершины запускает цикл для всех смежных вершин. Общее число смежных вершин в графе равно O (E). Таким образом, внутренний цикл выполняется O (V + E) раз. Следовательно, общая временная сложность этого алгоритма составляет O (V + E).

Упражнение: Приведенное выше решение распечатывает самые длинные расстояния, расширяет код и распечатывает пути.

Микро Фокус

Пожалуйста, напишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.

Рекомендуемые посты:

Самый длинный путь в направленном ациклическом графе

0.00 (0%) 0 votes