Cod sursa(job #2822082)

Utilizator davidbejenariu2David Bejenariu davidbejenariu2 Data 23 decembrie 2021 15:38:41
Problema Parcurgere DFS - componente conexe Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 21.77 kb
#ifndef LAB1_GRAPH_H
#define LAB1_GRAPH_H
#include <bits/stdc++.h>

using namespace std;
 
ifstream fin("dfs.in");
ofstream fout("dfs.out");

typedef pair<int, int> pii;
typedef pair<pii, int> ppi;
typedef pair<int, pii> pip;

const int inf = 1 << 30;

class DisjointSet {
private:
    int m_n;
    vector<int> m_root;
    vector<int> m_size;

public:
    // Constructors
    DisjointSet();
    explicit DisjointSet(int n);

    // Union & Find
    int find(int x);
    void unite(int x, int y);
};

DisjointSet::DisjointSet() : m_n(0), m_root(), m_size() {}

DisjointSet::DisjointSet(int n) : m_n(n) {
    m_root.resize(m_n + 1);
    m_size.resize(m_n + 1);

    for (int i = 1; i <= m_n; ++i) {
        m_root[i] = i;
        m_size[i] = 1;
    }
}

int DisjointSet::find(int x) {
    int rx = x, aux;

    while (rx != m_root[rx]) {
        rx = m_root[rx];
    }

    while (x != m_root[x]) {
        aux = m_root[x];
        m_root[x] = rx;
        x = aux;
    }

    return rx;
}

void DisjointSet::unite(int x, int y) {
    int rx = find(x);
    int ry = find(y);

    if (m_size[rx] > m_size[ry]) {
        m_root[ry] = rx;
        m_size[rx] += m_size[ry];
    } else {
        m_root[rx] = ry;
        m_size[ry] += m_size[rx];
    }
}

template<typename T>
class Graph {
public:
    // Constructors
    Graph();
    explicit Graph(int n);
    Graph(int n, vector<vector<T>> &ad);

    // addEdge Methods
    void addEdge(int v, int u);
    void addEdgeWeight(int v, int u, int weight);

    // Find Connected Components
    int components();

    // Find Minimum Distance from start to Other Vertices
    vector<int> minDist(int start);

    // Topological Sort
    vector<int> getTopologicalSort();

    // Find Strongly Connected Components
    vector<vector<int>> stronglyConnectedComponents();

    // Find Biconnected Components
    vector<vector<int>> biconnectedComponents();

    // Check if a graph can be built given the degree sequence
    static string canBuildGraph(vector<int> &v);

    // Optimal Paths
    pair<int, vector<int>> getOptimalVertices(int start, int end);

    // Minimum Spanning Tree (Kruskal's Algorithm)
    pair<int, vector<pii>> minimumSubtree();

    // Dijkstra's Algorithm
    vector<int> dijkstra();

    // Bellman-Ford Algorithm
    pair<int, vector<int>> bellmanFord();

    // Maximum Flow in a Network
    int getMaxFlow();

    // Roy-Floyd Algorithm
    vector<vector<int>> royFloyd();

    // Diameter of a Tree
    int diameter();

    // Eulerian Cycle
    vector<int> eulerianCycle(int edgeCount);

    // Minimum Weight Hamiltonian Circuit
    int minHamiltonianCircuit();

    // Maximum Bipartite Matching
    vector<pii> maxBipartiteMatching(int n);

    // Critical Connections in a Network (https://leetcode.com/problems/critical-connections-in-a-network/)
    vector<vector<int>> criticalConnections(int n, vector<vector<int>> &connections);

private:
    int m_n;
    vector<vector<T>> m_ad;
    vector<pair<int, T>> m_edges;

    // Utility Methods
    void DFS(int v, vector<bool> &vis);
    void topologicalSort(int v, vector<bool> &vis, vector<int> &stack);
    vector<vector<int>> getReversedGraph();
    void tDFS(int v, vector<vector<int>> &tAd, vector<bool> &vis, int compCount, vector<vector<int>> &comp);
    void bccDFS(int v, int parent, vector<int> &disc, vector<int> &low, vector<int> &stack, vector<vector<int>> &comp);
    static bool eligible(vector<int> &v);
    void findPaths(vector<vector<int>> &paths, vector<int> &path, vector<vector<int>> &parent, int current);
    void BFS(vector<vector<int>> &parents, int start);
    bool foundPath(vector<vector<int>> &c, vector<vector<int>> &flow, vector<int> &parent);
    static bool comp(pip &X, pip &Y);
    void treeDFS(int v, int d, int &dMax, int &vMax, vector<bool> &vis);
    int foundMatch(int l, vector<bool> &vis, vector<int> &matchL, vector<int> &matchR);
    void critDFS(int v, int parent, vector<int> &disc, vector<int> &low, vector<vector<int>> &cc);
    vector<vector<int>> getWeightMatrix();
};

// Constructors
template<typename T>
Graph<T>::Graph()  : m_n(0), m_ad(), m_edges() {}

template<typename T>
Graph<T>::Graph(int n) : m_n(n), m_edges() {
    m_ad.resize(m_n + 1);
}

template<typename T>
Graph<T>::Graph(int n, vector<vector<T>> &ad) :
        m_n(n), m_ad(ad), m_edges() {}

// addEdge Methods
template<typename T>
void Graph<T>::addEdge(int v, int u) {
    m_ad[v].push_back(u);
    m_edges.emplace_back(v, u);
}

template<typename T>
void Graph<T>::addEdgeWeight(int v, int u, int weight)  {
    m_ad[v].push_back({u, weight});
    m_edges.push_back({v, {u, weight}});
}

// Find Connected Components (using Depth-First Search)
template<typename T>
int Graph<T>::components() {
    int compCount = 0;
    vector<bool> vis(m_n, false);

    for (int i = 1; i <= m_n; ++i) {
        if (!vis[i]) {
            ++compCount;
            DFS(i, vis);
        }
    }

    return compCount;
}

// Find Minimum Distance from start to Other Vertices (using Breadth-First Search)
template<typename T>
vector<int> Graph<T>::minDist(int start) {
    vector<int> dist(m_n + 1, -1);
    queue<int> Q;
    int x;

    dist[start] = 0;
    Q.push(start);

    while (!Q.empty()) {
        x = Q.front(); Q.pop();

        for (auto &y : m_ad[x]) {
            if (dist[y] == -1) {
                dist[y] = dist[x] + 1;
                Q.push(y);
            }
        }
    }

    return dist;
}

// Topological Sort
template<typename T>
vector<int> Graph<T>::getTopologicalSort() {
    vector<bool> vis(m_n + 1, false);
    vector<int> stack;
    vector<int> ans;

    for (int i = 1; i <= m_n; ++i) {
        if (!vis[i]) {
            topologicalSort(i, vis, stack);
        }
    }

    for (int i = stack.size() - 1; i >= 0; --i) {
        ans.push_back(stack[i]);
    }

    return ans;
}

// Find Strongly Connected Components (Kosaraju's Algorithm)
template<typename T>
vector<vector<int>> Graph<T>::stronglyConnectedComponents() {
    vector<vector<int>> tAd = getReversedGraph();
    vector<bool> vis1(m_n + 1, false);
    vector<bool> vis2(m_n + 1, false);
    vector<int> stack;
    int compCount = 0;
    vector<vector<int>> comp;

    for (int i = 1; i <= m_n; ++i) {
        if (!vis1[i]) {
            topologicalSort(i, vis1, stack);
        }
    }

    for (int i = stack.size() - 1; i >= 0; --i) {
        if (!vis2[stack[i]]) {
            ++compCount;
            comp.emplace_back();

            tDFS(stack[i], tAd, vis2, compCount, comp);
        }
    }

    return comp;
}

// Find Biconnected Components
template<typename T>
vector<vector<int>> Graph<T>::biconnectedComponents() {
    vector<int> disc(m_n + 1, 0);
    vector<int> low(m_n + 1, 0);
    vector<int> stack;
    vector<vector<int>> comp;

    bccDFS(1, 0, disc, low, stack, comp);

    return comp;
}

// Check if a graph can be built given the degree sequence (Havel-Hakimi Algorithm)
template<typename T>
string Graph<T>::canBuildGraph(vector<int> &v) {
    if (!eligible(v)) {
        return "No";
    }

    sort(v.begin(), v.end(), greater<>());

    while (v[0]) {
        for (int i = 1; i <= v[0]; ++i) {
            if (v[i] == 0) {
                return "No";
            }

            --v[i];
        }

        v.erase(v.begin());
        sort(v.begin(), v.end(), greater<>());
    }

    return "Yes";
}

// Optimal Paths
template<typename T>
pair<int, vector<int>> Graph<T>::getOptimalVertices(int start, int end) {
    vector<vector<int>> paths;
    vector<int> path;
    vector<vector<int>> parents(m_n + 1);

    BFS(parents, start);
    findPaths(paths, path, parents, end);

    vector<int> check(m_n + 1, 0);
    auto pathCount = paths.size();
    int count = 0;

    for (auto &p : paths) {
        for (auto &v : p) {
            ++check[v];
        }
    }

    for (int i = 1; i <= m_n; ++i) {
        if (check[i] == pathCount) {
            ++count;
        }
    }

    vector<int> sol;

    for (int i = 1; i <= m_n; ++i) {
        if (check[i] == pathCount) {
            sol.push_back(i);
        }
    }

    return {count, sol};
}

// Minimum Spanning Tree (Kruskal's Algorithm)
template<typename T>
pair<int, vector<pii>> Graph<T>::minimumSubtree() {
    int totalCost = 0;
    DisjointSet S(m_n);
    vector<pair<int, int>> sol;

    sort(m_edges.begin(), m_edges.end(), comp);

    for (auto &edge : m_edges) {
        if (sol.size() == m_n - 1) {
            break;
        }

        int x = S.find(edge.first);
        int y = S.find(edge.second.first);

        if (x != y) {
            S.unite(x, y);

            totalCost += edge.second.second;
            sol.emplace_back(edge.first, edge.second.first);
        }
    }

    return {totalCost, sol};
}

// Dijkstra's Algorithm
template<typename T>
vector<int> Graph<T>::dijkstra() {
    vector<int> dist(m_n + 1, inf);
    vector<bool> vis(m_n + 1, false);
    priority_queue<pii, vector<pii>, greater<>> heap;

    dist[1] = 0;
    heap.push({0, 1});

    while (!heap.empty()) {
        int current = heap.top().second;
        heap.pop();

        if (!vis[current]) {
            vis[current] = true;

            for (auto &w : m_ad[current]) {
                if (dist[current] + w.second < dist[w.first]) {
                    dist[w.first] = dist[current] + w.second;
                    heap.push({dist[w.first], w.first});
                }
            }
        }
    }

    return dist;
}

// Bellman-Ford Algorithm
template<typename T>
pair<int, vector<int>> Graph<T>::bellmanFord() {
    vector<int> dist(m_n + 1, inf);
    vector<bool> inHeap(m_n + 1, false);
    vector<int> count(m_n + 1, 0);
    priority_queue<pii, vector<pii>, greater<>> heap;
    bool foundCycle = false;

    dist[1] = 0;
    inHeap[1] = true;
    heap.push({0, 1});

    while (!heap.empty() && !foundCycle) {
        int current = heap.top().second;
        heap.pop();

        inHeap[current] = false;

        for (auto &w : m_ad[current]) {
            if (dist[current] + w.second < dist[w.first]) {
                if (!inHeap[w.first]) {
                    ++count[w.first];
                    inHeap[w.first] = true;

                    heap.push({dist[w.first], w.first});

                    if (count[w.first] > m_n) {
                        foundCycle = true;
                    }
                }

                dist[w.first] = dist[current] + w.second;
            }
        }
    }

    return {foundCycle, dist};
}

// Maximum Flow in a Network (Edmonds-Karp Algorithm)
template<typename T>
int Graph<T>::getMaxFlow()  {
    int maxFlow = 0;
    auto c = getWeightMatrix();
    vector<int> parent(m_n + 1);
    vector<vector<int>> flow(m_n + 1);

    for (int i = 1; i <= m_n; ++i) {
        flow[i].resize(m_n + 1, 0);
    }

    while (foundPath(c, flow, parent)) {
        for (auto &p : m_ad[m_n]) {
            auto w = p.first;

            if (c[w][m_n] == flow[w][m_n] || !parent[w]) {
                continue;
            }

            int minFlow = c[w][m_n] - flow[w][m_n];

            for (int v = w; v != 1; v = parent[v]) {
                minFlow = min(minFlow, c[parent[v]][v] - flow[parent[v]][v]);
            }

            if (minFlow == 0) {
                continue;
            }

            flow[w][m_n] += minFlow;
            flow[m_n][w] -= minFlow;

            for (int v = w; v != 1; v = parent[v]) {
                flow[parent[v]][v] += minFlow;
                flow[v][parent[v]] -= minFlow;
            }

            maxFlow += minFlow;
        }
    }

    return maxFlow;
}

// Roy-Floyd Algorithm
template<typename T>
vector<vector<int>> Graph<T>::royFloyd() {
    int i, j, k;

    for (k = 1; k <= m_n; ++k) {
        for (i = 1; i <= m_n; ++i) {
            for (j = 1; j <= m_n; ++j) {
                m_ad[i][j] = min(m_ad[i][j], m_ad[i][k] + m_ad[k][j]);
            }
        }
    }

    return m_ad;
}

// Diameter of a Tree
template<typename T>
int Graph<T>::diameter()  {
    int dMax = 1, vMax;
    vector<bool> vis(m_n + 1, false);

    treeDFS(1, 1, dMax, vMax, vis);

    vis.assign(m_n + 1, false);
    dMax = 1;

    treeDFS(vMax, 1, dMax, vMax, vis);

    return dMax;
}

// Eulerian Cycle
template<typename T>
vector<int> Graph<T>::eulerianCycle(int edgeCount) {
    for (int i = 1; i <= m_n; ++i) {
        if (m_ad[i].size() & 1) {
            return {-1};
        }
    }

    vector<int> ans;
    vector<bool> vis(edgeCount + 1);
    stack<int> s;

    s.push(1);

    while (!s.empty()) {
        int current = s.top();

        while (!m_ad[current].empty() && vis[m_ad[current].back().second]) {
            m_ad[current].pop_back();
        }

        if (!m_ad[current].empty()) {
            pii edge = m_ad[current].back();

            vis[edge.second] = true;
            s.push(edge.first);
        } else {
            ans.push_back(current);
            s.pop();
        }
    }

    return ans;
}

// Minimum Weight Hamiltonian Circuit (Dynamic Programming)
template<typename T>
int Graph<T>::minHamiltonianCircuit() {
    auto weight = getWeightMatrix();
    vector<vector<int>> dp(1 << m_n);

    for (int i = 0; i < 1 << m_n; ++i) {
        dp[i].resize(m_n, inf);
    }

    dp[1][0] = 0;

    for (int i = 1; i < 1 << m_n; ++i) {
        for (int j = 0; j < m_n; ++j) {
            if (dp[i][j] != inf) {
                for (auto &p : m_ad[j]) {
                    int w = p.first;

                    if (!(i & (1 << w))) { // nodul w nu face parte din drumul reprezentat de i
                        dp[i | (1 << w)][w] = min(dp[i | (1 << w)][w], dp[i][j] + weight[j][w]);
                    }
                }
            }
        }
    }

    vector<int> endpoints;
    int ans = inf;

    for (int i = 1; i < m_n; ++i) {
        for (auto &w : m_ad[i]) {
            if (w.first == 0) {
                endpoints.push_back(i);
                break;
            }
        }
    }

    for (auto &e : endpoints) {
        ans = min(ans, dp[(1 << m_n) - 1][e] + weight[e][0]);
    }

    return ans;
}

// Maximum Bipartite Matching
template<typename T>
vector<pii> Graph<T>::maxBipartiteMatching(int n) {
    vector<int> matchL(m_n + 1, -1);
    vector<int> matchR(m_n + 1, -1);
    vector<bool> vis(m_n + 1);
    int found = 1;

    while (found) {
        found = 0;
        fill(vis.begin(), vis.end(), 0);

        for (int l = 1; l <= n; ++l) {
            if (matchL[l] == -1) {
                found |= foundMatch(l, vis, matchL, matchR);
            }
        }
    }

    vector<pii> ans;

    for (int l = 1; l <= n; ++l) {
        if (matchL[l] != -1) {
            ans.emplace_back(l, matchL[l]);
        }
    }

    return ans;
}

// Critical Connections in a Network
template<typename T>
vector<vector<int>> Graph<T>::criticalConnections(int n, vector<vector<int>> &connections) {
    vector<vector<int>> ad(n);
    vector<vector<int>> cc;

    for (auto &connection : connections) {
        ad[connection[0]].push_back(connection[1]);
        ad[connection[1]].push_back(connection[0]);
    }

    m_n = n;
    m_ad = ad;

    vector<int> disc(m_n, 0);
    vector<int> low(m_n, 0);

    DFS(0, -1, disc, low, cc);

    return cc;
}

// Utilities
template<typename T>
void Graph<T>::DFS(int v, vector<bool> &vis) {
    vis[v] = true;

    for (auto &x : m_ad[v]) {
        if (!vis[x]) {
            DFS(x, vis);
        }
    }
}

template<typename T>
void Graph<T>::topologicalSort(int v, vector<bool> &vis, vector<int> &stack) {
    vis[v] = true;

    for (auto &x : m_ad[v]) {
        if (!vis[x]) {
            topologicalSort(x, vis, stack);
        }
    }

    stack.push_back(v);
}

template<typename T>
vector<vector<int>> Graph<T>::getReversedGraph() {
    vector<vector<int>> tAd(m_n + 1);

    for (int i = 1; i <= m_n; ++i) {
        for (auto &w : m_ad[i]) {
            tAd[w].push_back(i);
        }
    }

    return tAd;
}

template<typename T>
void Graph<T>::tDFS(int v, vector<vector<int>> &tAd, vector<bool> &vis, int compCount, vector<vector<int>> &comp) {
    vis[v] = true;
    comp[compCount - 1].push_back(v);

    for (auto &x : tAd[v]) {
        if (!vis[x]) {
            tDFS(x, tAd, vis, compCount, comp);
        }
    }
}

template<typename T>
void Graph<T>::bccDFS(int v, int parent, vector<int> &disc, vector<int> &low, vector<int> &stack,
                      vector<vector<int>> &comp) {
    static int time = 0;
    int children = 0;

    disc[v] = low[v] = ++time;

    for (auto &w : m_ad[v]) {
        if (w == parent) continue;

        if (!disc[w]) {
            ++children;
            stack.push_back(w);
            bccDFS(w, v, disc, low, stack, comp);
            low[v] = min(low[v], low[w]);

            if (low[w] >= disc[v]) {
                comp.emplace_back();
                stack.push_back(v);

                while (!stack.empty() && stack.back() != w) {
                    comp[comp.size() - 1].push_back(stack.back());
                    stack.pop_back();
                }

                if (!stack.empty()) {
                    comp[comp.size() - 1].push_back(stack.back());
                    stack.pop_back();
                }
            }
        } else if (w != parent) {
            low[v] = min(low[v], disc[w]);
        }
    }
}

template<typename T>
bool Graph<T>::eligible(vector<int> &v) {
    int s = 0;
    auto n = v.size();

    for (auto &x : v) {
        if (x > n - 1) {
            return false;
        }

        s += x;
    }

    return s % 2 == 0;
}

template<typename T>
void Graph<T>::findPaths(vector<vector<int>> &paths, vector<int> &path, vector<vector<int>> &parent, int current) {
    if (current == -1) {
        paths.push_back(path);
        return;
    }

    for (auto &p : parent[current]) {
        path.push_back(current);
        findPaths(paths, path, parent, p);
        path.pop_back();
    }
}

template<typename T>
void Graph<T>::BFS(vector<vector<int>> &parents, int start) {
    vector<int> dist(m_n + 1, inf);
    queue<int> Q;

    Q.push(start);
    parents[start] = {-1};
    dist[start] = 0;

    while (!Q.empty()) {
        int current = Q.front(); Q.pop();

        for (auto &x : m_ad[current]) {
            if (dist[current] + 1 < dist[x]) {
                dist[x] = dist[current] + 1;
                Q.push(x);

                parents[x].clear();
                parents[x].push_back(current);
            } else if (dist[x] == dist[current] + 1) {
                parents[x].push_back(current);
            }
        }
    }
}

template<typename T>
bool Graph<T>::foundPath(vector<vector<int>> &c, vector<vector<int>> &flow, vector<int> &parent) {
    queue<int> Q;
    vector<bool> vis(m_n + 1, false);

    parent[1] = -1;
    Q.push(1);

    while (!Q.empty()) {
        int current = Q.front(); Q.pop();
        vis[current] = true;

        if (current == m_n) {
            continue;
        }

        for (auto &w : m_ad[current]) {
            if (!vis[w.first] && flow[current][w.first] < c[current][w.first]) {
                parent[w.first] = current;
                Q.push(w.first);
            }
        }
    }

    return vis[m_n];
}

template<typename T>
bool Graph<T>::comp(pip &X, pip &Y) {
    return X.second.second < Y.second.second;
}

template<typename T>
void Graph<T>::treeDFS(int v, int d, int &dMax, int &vMax, vector<bool> &vis) {
    if (d > dMax) {
        dMax = d;
        vMax = v;
    }

    vis[v] = true;

    for (auto &w : m_ad[v]) {
        if (!vis[w]) {
            treeDFS(w, d + 1, dMax, vMax, vis);
        }
    }
}

template<typename T>
int Graph<T>::foundMatch(int l, vector<bool> &vis, vector<int> &matchL, vector<int> &matchR) {
    if (!vis[l]) {
        vis[l] = true;

        for (auto &r : m_ad[l]) {
            if (matchR[r] == -1) {
                matchL[l] = r;
                matchR[r] = l;

                return 1;
            }
        }

        for (auto &r : m_ad[l]) {
            if (foundMatch(matchR[r], vis, matchL, matchR)) {
                matchL[l] = r;
                matchR[r] = l;

                return 1;
            }
        }
    }

    return 0;
}

template<typename T>
void Graph<T>::critDFS(int v, int parent, vector<int> &disc, vector<int> &low, vector<vector<int>> &cc) {
    static int time = 0;
    disc[v] = low[v] = ++time;

    for (auto &w : m_ad[v]) {
        if (w == parent) continue;

        if (!disc[w]) {
            critDFS(w, v, disc, low, cc);
            low[v] = min(low[v], low[w]);

            if (low[w] > disc[v]) {
                vector<int> e;
                e.push_back(v);
                e.push_back(w);

                cc.push_back(e);
            }
        } else if (w != parent) {
            low[v] = min(low[v], disc[w]);
        }
    }
}

template<typename T>
vector<vector<int>> Graph<T>::getWeightMatrix() {
    vector<vector<int>> weight(m_n + 1);

    for (int i = 0; i < m_n; ++i) {
        weight[i].resize(m_n + 1, 0);
    }

    for (int i = 0; i < m_n; ++i) {
        for (auto &p : m_ad[i]) {
            weight[i][p.first] = p.second;
        }
    }

    return weight;
}

int main() {
    int n, m, x, y;
 
    fin >> n >> m;
 
    Graph<int> G(n);
 
    for (int i = 1; i <= m; ++i) {
        fin >> x >> y;
 
        G.addEdge(x, y);
        G.addEdge(y, x);
    }

    fout << G.components();
 
    return 0;
}