Website Summary Files Commits Branches @commit @diff @stats
path: root / Seminar13 / src / mst-prim.cpp
blob: a89bc26a2fca4fe5117f95782f7c5ea4de681a4b (plain) (blame)
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include "../../Seminar12/src/graph_impl/weighted_graph/weighted_graph.h"
#include <queue>
#include <iostream>
#include <limits.h>

using vertex_t = weighted_graph::vertex_t;
using vertex_index_t = weighted_graph::vertex_index_t;
using weight_t = weighted_graph::weight_t;

struct mst_info
{
    std::vector<vertex_index_t> tree;
    int cost = 0;
};

mst_info prim(const weighted_graph& g, vertex_index_t start = 0)
{
    mst_info result;

    if(g.vertex_count() == 0)
        return result;
    
    std::vector<bool> visited(g.vertex_count(), false);
    result.tree.resize(g.vertex_count(), -1);
    // min_cost[i] = minimum cost found!
    std::vector<weight_t> min_cost(g.vertex_count(), INT_MAX);

    struct vertex_comparator
    {
        bool operator()(const vertex_t& lhs, const vertex_t& rhs) const
        {
            return lhs.second > rhs.second;
        }
    };

    std::priority_queue<vertex_t, std::vector<vertex_t>, vertex_comparator> p;

    // initialize structures:
    p.push({start, 0});
    min_cost[start] = 0;

    size_t found_edges = 0;

    while(found_edges != g.vertex_count())
    {
        vertex_index_t current_vertex = p.top().first;
        weight_t current_weight       = p.top().second;

        p.pop();

        if(visited[current_vertex])
            continue;
        
        visited[current_vertex] = true;
        result.cost += current_weight;
        ++found_edges;

        const auto& adjacent = g.adjacent(current_vertex);

        for(const vertex_t& vertex : adjacent)
        {
            vertex_index_t found_index = vertex.first;
            weight_t found_weight      = vertex.second;

            if(!visited[found_index] && found_weight < min_cost[found_index])
            {
                result.tree[found_index] = current_vertex;
                p.push({found_index, found_weight});
                min_cost[found_index] = found_weight;
            }
        }
    }

    return result;
}

int main()
{
    weighted_graph g(7, false);

    g.add_edge(0, 1, 4);
    g.add_edge(0, 2, 3);
    g.add_edge(1, 2, 1);
    g.add_edge(1, 3, 2);
    g.add_edge(2, 4, 5);
    g.add_edge(3, 4, 6);
    g.add_edge(3, 5, 7);
    g.add_edge(4, 6, 8);
    g.add_edge(5, 6, 4);


    auto result = prim(g);

    std::cout << "Total cost of MST: " << result.cost << '\n';

    std::cout << "Tree structure (parent array): ";
    for (const auto x : result.tree)
    {
        std::cout << x << " ";
    }

    std::cout << '\n';

    return 0;
}