Cod sursa(job #3272207)

Utilizator AndreiLeusteanLeustean Andrei AndreiLeustean Data 28 ianuarie 2025 20:59:55
Problema Parcurgere DFS - componente conexe Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 34.07 kb
#include <bits/stdc++.h>

using namespace std;

ifstream in("citire.in");
const int infinity = numeric_limits<int>::max();
const int infinitytMin = numeric_limits<int>::min();

// muchie de la x la y cu costul cost
struct Muchie
{
    int x, y;
    int cost = 0;
    int capacitate = -1;
    int flux = -1;

    Muchie() = default;

    Muchie(int x, int y, int cost)
    {
        this->x = x;
        this->y = y;
        this->cost = cost;
    }

    Muchie(int x, int y)
    {
        this->x = x;
        this->y = y;
    }

    Muchie(int x, int y, int flux, int capacitate)
    {
        this->x = x;
        this->y = y;
        this->flux = flux;
        this->capacitate = capacitate;
    }
};

bool comparison(Muchie m1, Muchie m2)
{
    return m1.cost < m2.cost;
}

struct Nod
{
    int nod;
    int cost = 0;
    int capacitate = -1;
    int flux = -1;

    Nod() = default;
    Nod(int nod) { this->nod = nod; }
    Nod(int nod, int cost)
    {
        this->nod = nod;
        this->cost = cost;
    }

    Nod(int nod, int flux, int capacitate)
    {
        this->nod = nod;
        this->flux = flux;
        this->capacitate = capacitate;
    }

    bool operator<(const Nod &obj) const
    {
        return this->cost > obj.cost; //> pt min-heap
    }
};

class Graf
{
public:
    int nrNoduri;
    int nrMuchii;
    vector<bool> vizitat;
    vector<int> grad_intern;
    vector<int> grad_extern;
    vector<vector<Nod>> lista_adiacenta;
    vector<Muchie> muchii;

    Graf() = default;

    Graf(int nrNoduri)
    {
        this->nrNoduri = nrNoduri;
        vizitat.resize(nrNoduri + 1);
        grad_intern.resize(nrNoduri + 1, 0);
        grad_extern.resize(nrNoduri + 1, 0);
        lista_adiacenta.resize(nrNoduri + 1);
    }
    Graf(int nrNoduri, int nrMuchii)
    {
        this->nrMuchii = nrMuchii;
        this->nrNoduri = nrNoduri;
        vizitat.resize(nrNoduri + 1);
        grad_intern.resize(nrNoduri + 1, 0);
        grad_extern.resize(nrNoduri + 1, 0);
        lista_adiacenta.resize(nrNoduri + 1);
    }
    void calculeazaGrad()
    {
        for (int nod = 1; nod <= nrNoduri; nod++)
            grad_extern[nod] = grad_intern[nod] = 0;
        for (int nod = 1; nod <= nrNoduri; nod++)
        {
            for (auto vecin : lista_adiacenta[nod])
            {
                grad_intern[vecin.nod] += 1;
                grad_extern[nod] += 1;
            }
        }
    }
    void dfs(int start, stack<int> &stiva)
    {
        vizitat[start] = true;
        for (auto vecin : lista_adiacenta[start])
        {
            if (vizitat[vecin.nod] == false)
            {
                dfs(vecin.nod, stiva);
            }
        }
        stiva.push(start);
    }

    void iterativeDFS(int start, vector<int> &tati)
    {
        int n = nrNoduri;
        vector<bool> vizitat(n + 1, false);
        stack<int> stack;
        stack.push(start);

        while (!stack.empty())
        {
            int nod = stack.top();
            stack.pop();

            if (vizitat[nod] == false)
            {
                cout << nod;
                vizitat[nod] = true;
            }

            for (auto vecin : lista_adiacenta[nod])
                if (vizitat[vecin.nod] == false)
                    stack.push(vecin.nod);
        }
    }

    void bfs(int start, vector<int> &tata)
    {
        queue<int> coada;
        coada.push(start);
        vizitat[start] = 1;
        while (!coada.empty())
        {
            int nod = coada.front();
            coada.pop();
            for (auto vecin : lista_adiacenta[nod])
            {
                if (vizitat[vecin.nod] == 0)
                {
                    coada.push(vecin.nod);
                    vizitat[vecin.nod] = 1;
                    tata[vecin.nod] = nod;
                }
            }
        }
    }

    vector<int> sortareTopologica()
    {
        vector<int> noduri_start;
        stack<int> stiva;
        for (int nod = 1; nod <= nrNoduri; nod++)
        {
            if (grad_intern[nod] == 0)
            {
                noduri_start.push_back(nod);
            }
        }

        for (auto nod : noduri_start)
        {
            dfs(nod, stiva);
        }

        vector<int> sortaretopologica;
        while (!stiva.empty())
        {
            sortaretopologica.push_back(stiva.top());
            stiva.pop();
        }
        return sortaretopologica;
    }

    void printGraf()
    {
        for (int i = 1; i <= nrNoduri; i++)
        {
            cout << i << ": ";
            for (auto nod : lista_adiacenta[i])
                cout << nod.nod << "(" << nod.cost << ") ";
            cout << endl;
        }
    }

    void printGrad()
    {
        for (int i = 1; i <= nrNoduri; i++)
        {
            cout << i << "-> grad intern = " << grad_intern[i] << ", grad extern = " << grad_extern[i] << endl;
        }
    }

    // DAG
    void DagDrumMaxim(int sursa, vector<int> &drum, vector<int> &tata)
    {
        drum.resize(nrNoduri + 1);
        tata.resize(nrNoduri + 1);
        for (int i = 1; i <= nrNoduri; i++)
        {
            drum[i] = -1;
            tata[i] = 0;
        }
        drum[sursa] = 0;
        vector<int> top = sortareTopologica();
        for (auto nod : top)
        {
            for (auto vecin : lista_adiacenta[nod])
            {
                if (drum[nod] + vecin.cost > drum[vecin.nod])
                {
                    drum[vecin.nod] = drum[nod] + vecin.cost;
                    tata[vecin.nod] = nod;
                }
            }
        }
    }

    void Djikstra(int sursa, vector<int> &drum, vector<int> &tata)
    {
        drum.clear();
        tata.clear();
        drum.resize(nrNoduri + 1);
        tata.resize(nrNoduri + 1);
        for (int i = 1; i <= nrNoduri; i++)
        {
            drum[i] = infinity;
            tata[i] = 0;
        }
        drum[sursa] = 0;

        auto cmp = [&](int nod1, int nod2)
        { return drum[nod1] > drum[nod2]; };
        priority_queue<int, vector<int>, decltype(cmp)> pq(cmp);

        // daca am adaugat o sursa imaginara si doresc sa pornesc din locuri multiple :
        // for (int i = 1; i <= nrNoduri; i++)
        //     pq.push(i);

        pq.push(sursa);
        while (!pq.empty())
        {
            int nod = pq.top();
            pq.pop();

            for (auto vecin : lista_adiacenta[nod])
            {
                if (drum[nod] + vecin.cost < drum[vecin.nod])
                {
                    drum[vecin.nod] = drum[nod] + vecin.cost;
                    pq.push(vecin.nod);
                    tata[vecin.nod] = nod;
                }
            }
        }
    }

    // intoarce false daca contine circuit negativ, true daca nu
    bool BellmanFord(int sursa, vector<int> &drum, vector<int> &tata, int &negativStart)
    {
        drum.resize(nrNoduri + 1);
        tata.resize(nrNoduri + 1);
        for (int i = 1; i <= nrNoduri; i++)
        {
            drum[i] = infinity;
            tata[i] = 0;
        }
        drum[sursa] = 0;
        for (int k = 1; k <= nrNoduri - 1; k++)
        {
            for (auto muchie : muchii)
            {
                if (drum[muchie.x] < infinity && drum[muchie.x] + muchie.cost < drum[muchie.y])
                {
                    drum[muchie.y] = drum[muchie.x] + muchie.cost;
                    tata[muchie.y] = muchie.x;
                }
            }
        }
        // a n a rulare a algoritmului pentru a detecta ciclul negativ
        for (auto muchie : muchii)
        {
            if (drum[muchie.x] < infinity && drum[muchie.x] + muchie.cost < drum[muchie.y])
            {
                drum[muchie.y] = drum[muchie.x] + muchie.cost;
                tata[muchie.y] = muchie.x;
                negativStart = muchie.y;
                return false;
            }
        }
        return true;
    }

    // BellmanFord cu queue -> mai rapid decat primul
    bool BellmanFord2(int sursa, vector<int> &drum, vector<int> &tata, int &negativStart)
    {
        drum.resize(nrNoduri + 1);
        tata.resize(nrNoduri + 1);
        for (int i = 1; i <= nrNoduri; i++)
        {
            drum[i] = infinity;
            tata[i] = 0;
        }
        drum[sursa] = 0;
        vector<bool> inQueue(nrNoduri + 1, false);
        queue<int> q;
        q.push(sursa);
        inQueue[sursa] = true;
        vector<int> lungime(nrNoduri + 1, 0);
        while (!q.empty())
        {
            int nod = q.front();
            q.pop();
            inQueue[nod] = false;
            for (auto vecin : lista_adiacenta[nod])
            {
                if (drum[nod] < infinity && drum[nod] + vecin.cost < drum[vecin.nod])
                {
                    drum[vecin.nod] = drum[nod] + vecin.cost;
                    tata[vecin.nod] = nod;
                    if (inQueue[vecin.nod] == false)
                    {
                        q.push(vecin.nod);
                        inQueue[vecin.nod] = true;
                    }
                    lungime[vecin.nod] = lungime[nod] + 1;
                    if (lungime[vecin.nod] > nrNoduri - 1)
                    {
                        negativStart = vecin.nod;
                        return false;
                    }
                }
            }
        }
        return true;
    }

    void afisareDrum(int start, int end, vector<int> tata)
    {
        // cout << start << " " << end << endl;
        // for (int i = 1; i <= nrNoduri; i++)
        //     cout << tata[i] << " ";
        // cout << endl;
        vector<int> drum;
        if (start != end) // daca e circuit nu trebuie sa punem finalul de 2 ori
            drum.push_back(end);
        while (tata[end] != start)
        {
            end = tata[end];
            drum.push_back(end);
        }
        drum.push_back(start);
        for (int i = drum.size() - 1; i >= 0; i--)
            cout << drum[i] << " ";
    }

    // daca dupa algoritm avem drumuri[i][i] < 0 pentru un i => circuit negativ
    // am decis ca daca nu exista drum atunci in matrice e 0
    // de asemenea drumuri[i][i] = lantul minim folosin cel putin un arc sau infinit daca nu exista un
    // lant de lungime nevida de la i la i ( circuit practic )
    void FloydWarshall(vector<vector<int>> &drumuri, vector<vector<int>> &predecesor)
    {
        drumuri.resize(nrNoduri + 1);
        predecesor.resize(nrNoduri + 1);
        for (int nod = 1; nod <= nrNoduri; nod++)
        {
            drumuri[nod].resize(nrNoduri + 1, infinity);
            predecesor[nod].resize(nrNoduri + 1, 0);
            for (auto vecin : lista_adiacenta[nod])
            {
                drumuri[nod][vecin.nod] = vecin.cost;
                predecesor[nod][vecin.nod] = nod;
            }
        }
        // for (int i = 1; i <= nrNoduri; i++)
        //     drumuri[i][i] = 0;
        for (int k = 1; k <= nrNoduri; k++)
        {
            for (int i = 1; i <= nrNoduri; i++)
            {
                for (int j = 1; j <= nrNoduri; j++)
                {
                    if (drumuri[i][k] < infinity && drumuri[k][j] < infinity)
                    {
                        if (drumuri[i][j] > drumuri[i][k] + drumuri[k][j])
                        {
                            drumuri[i][j] = drumuri[i][k] + drumuri[k][j];
                            predecesor[i][j] = predecesor[k][j];
                        }
                    }
                }
            }
        }

        for (int i = 1; i <= nrNoduri; i++)
        {
            for (int j = 1; j <= nrNoduri; j++)
            {
                if (drumuri[i][j] == infinity)
                    drumuri[i][j] = 0; // nu exista drum
            }
        }
    }

    void drumMat(int x, int y, vector<vector<int>> predecesor)
    {
        if (x != y)
            drumMat(x, predecesor[x][y], predecesor);
        cout << y << " ";
    }

    void afisCircuitMat(int x, int y, vector<vector<int>> predecesor)
    {
        if (predecesor[x][y] != x)
            afisCircuitMat(x, predecesor[x][y], predecesor);
        cout << y << " ";
    }

    void afisareDrumuriMat(vector<vector<int>> drumuri, vector<vector<int>> predecesor)
    {
        for (int i = 1; i <= nrNoduri; i++)
        {
            cout << i << ": \n";
            for (int j = 1; j <= nrNoduri; j++)
            {
                cout << "       " << j << ": ";
                if (drumuri[i][j] == 0)
                    cout << "nu exista drum\n";
                else
                {
                    drumMat(i, j, predecesor);
                    cout << " cu costul: " << drumuri[i][j] << endl;
                }
            }
        }
    }

    long long Prim(int start, vector<Muchie> &muchiiApcm)
    {
        vector<int> d(nrNoduri + 1, infinity);
        vector<int> tata(nrNoduri + 1, -1);
        vector<bool> inHeap(nrNoduri + 1, true);

        auto cmp = [&](int nod1, int nod2)
        { return d[nod1] > d[nod2]; };
        priority_queue<Nod> minHeap;

        d[start] = 0;
        minHeap.push(Nod(start, d[start]));

        while (!minHeap.empty())
        {
            Nod u = minHeap.top();
            minHeap.pop();
            inHeap[u.nod] = false;

            for (auto vecin : lista_adiacenta[u.nod])
            {
                if (inHeap[vecin.nod] && vecin.cost < d[vecin.nod])
                {
                    d[vecin.nod] = vecin.cost;
                    tata[vecin.nod] = u.nod;
                    minHeap.push(Nod(vecin.nod, d[vecin.nod]));
                }
            }
        }
        long long cost = 0;
        for (int i = 1; i <= nrNoduri; i++)
            if (i != start)
            {
                muchiiApcm.push_back(Muchie(i, tata[i]));
                cost += d[i];
            }
        return cost;
    }

    int Repr(int x, vector<int> &tata)
    {
        if (tata[x] == 0)
            return x;
        tata[x] = Repr(tata[x], tata);
        return tata[x];
    }

    void Union(int x, int y, vector<int> &tata, vector<int> &h)
    {
        int rx, ry;
        rx = Repr(x, tata);
        ry = Repr(y, tata);
        if (h[rx] > h[ry])
        {
            tata[ry] = rx;
        }
        else
        {
            tata[rx] = ry;
            if (h[rx] == h[ry])
                h[rx] = h[ry] + 1;
        }
    }

    long long Kruskal(vector<Muchie> &apcm, vector<vector<Nod>> &apcmListaAdiacenta, vector<int> &tata)
    {
        sort(muchii.begin(), muchii.end(), comparison);
        tata.clear();
        tata.resize(nrNoduri + 1, 0);
        vector<int> inaltime(nrNoduri + 1, 0);
        apcmListaAdiacenta.clear();
        apcm.clear();
        apcmListaAdiacenta.resize(nrNoduri + 1);

        int nrSelectii = 0;
        long long costTotal = 0;

        for (auto muchie : muchii)
        {
            if (Repr(muchie.x, tata) != Repr(muchie.y, tata))
            {
                apcm.push_back(muchie);
                apcmListaAdiacenta[muchie.x].push_back(Nod(muchie.y, muchie.cost));
                apcmListaAdiacenta[muchie.y].push_back(Nod(muchie.x, muchie.cost));
                costTotal += muchie.cost;
                Union(muchie.x, muchie.y, tata, inaltime);
                nrSelectii += 1;
                if (nrSelectii == nrNoduri - 1)
                    return costTotal;
            }
        }
        return -1;
    }

    void dfsNivel(int i, vector<int> &nivel, vector<int> &nivel_min, vector<int> &tata)
    {
        vizitat[i] = true;
        nivel_min[i] = nivel[i];
        for (auto vecin : lista_adiacenta[i])
        {
            if (vizitat[vecin.nod] == false) // i -> vecin muchie de avansare
            {
                tata[vecin.nod] = i;
                nivel[vecin.nod] = nivel[i] + 1;
                dfsNivel(vecin.nod, nivel, nivel_min, tata);

                nivel_min[i] = min(nivel_min[vecin.nod], nivel_min[i]);

                // if (nivel_min[vecin.nod] > nivel[i])
                //     cout << i << " " << vecin.nod << endl;
            }
            else if (nivel[vecin.nod] < nivel[i] - 1) // i -> vecin muchie de intoarcere
                nivel_min[i] = min(nivel_min[i], nivel[vecin.nod]);
            // else if (nivel[vecin.nod] > nivel[i])
            // {
            //     nivel_min[i] = min(nivel_min[i], nivel_min[vecin.nod]);
            // }
        }
    }

    void muchiiCritice()
    {
        vector<int> nivel(nrNoduri + 1, 0), nivel_min(nrNoduri + 1, 0), tata(nrNoduri + 1, -1);
        dfsNivel(1, nivel, nivel_min, tata);
        for (int i = 1; i <= nrNoduri; i++)
        {
            if (tata[i] != -1 && nivel_min[i] > nivel[tata[i]])
                cout << tata[i] << " " << i << endl;
        }
    }

    void puncteCritice()
    {

        vector<int> nivel(nrNoduri + 1, 0), nivel_min(nrNoduri + 1, 0), tata(nrNoduri + 1, -1);
        for (int i = 1; i <= nrNoduri; i++)
            vizitat[i] = false;
        dfsNivel(1, nivel, nivel_min, tata);
        int nrfii = 0;
        for (int i = 1; i <= nrNoduri; i++)
            if (tata[i] == 1)
                nrfii++;

        if (nrfii >= 2)
            cout << 1 << endl;
        for (int i = 2; i <= nrNoduri; i++)
        {
            bool este = false;
            for (auto vecin : lista_adiacenta[i])
            {
                if (nivel_min[vecin.nod] >= nivel[i] && tata[vecin.nod] == i)
                {
                    este = true;
                    break;
                }
            }
            if (este)
                cout << i << " ";
        }
    }

    void dfsBiconex(int i, vector<int> &nivel, vector<int> &nivel_min, stack<Muchie> &stiva)
    {
        vizitat[i] = true;
        nivel_min[i] = nivel[i];
        for (auto vecin : lista_adiacenta[i])
        {
            if (vizitat[vecin.nod] == false) // ij -> vecin muchie de avansare
            {
                nivel[vecin.nod] = nivel[i] + 1;
                stiva.push(Muchie(i, vecin.nod));
                dfsBiconex(vecin.nod, nivel, nivel_min, stiva);

                nivel_min[i] = min(nivel_min[vecin.nod], nivel_min[i]);

                if (nivel_min[vecin.nod] >= nivel[i])
                {
                    // adica avem punct critic
                    // cout << i << endl; pct critice cu radacina ( nu e neaparat )
                    Muchie top = stiva.top();
                    while (!(top.x == i && top.y == vecin.nod))
                    {
                        cout << top.x << " " << top.y << endl;
                        stiva.pop();
                        top = stiva.top();
                    }
                    cout << top.x << " " << top.y << endl;
                    stiva.pop();
                    cout << endl;
                }
            }
            else if (nivel[vecin.nod] < nivel[i] - 1) // i -> vecin muchie de intoarcere
            {
                nivel_min[i] = min(nivel_min[i], nivel[vecin.nod]);
                stiva.push(Muchie(i, vecin.nod));
            }
            // else if (nivel[vecin.nod] > nivel[i])
            // {
            //     nivel_min[i] = min(nivel_min[i], nivel_min[vecin.nod]);
            // }
        }
    }

    void componenteBiconexe()
    {

        vector<int> nivel(nrNoduri + 1, 0), nivel_min(nrNoduri + 1, 0);
        stack<Muchie> stiva;
        for (int i = 1; i <= nrNoduri; i++)
            vizitat[i] = false;
        dfsBiconex(1, nivel, nivel_min, stiva);
        while (!stiva.empty())
        {
            cout << stiva.top().x << " " << stiva.top().y << endl;
            stiva.pop();
        }
    }

    void removeMuchie(int x, int y)
    {
        int found = -1;
        for (int i = 0; i < lista_adiacenta[x].size() && found == -1; i++)
            if (lista_adiacenta[x][i].nod == y)
                found = i;
        if (found != -1)
            lista_adiacenta[x].erase(lista_adiacenta[x].begin() + found);
        found = -1;
        for (int i = 0; i < lista_adiacenta[y].size() && found == -1; i++)
            if (lista_adiacenta[y][i].nod == x)
                found = i;
        if (found != -1)
            lista_adiacenta[y].erase(lista_adiacenta[y].begin() + found);
        calculeazaGrad();
        nrMuchii -= 1;
        found = -1;
        for (int i = 0; i < muchii.size() && found == -1; i++)
            if (muchii[i].x == x && muchii[i].y == y)
                found = i;
        if (found != -1)
            muchii.erase(muchii.begin() + found);
    }

    void colorare()
    {
        for (int i = 1; i <= nrNoduri; i++)
            vizitat[i] = false;
        calculeazaGrad();
        queue<int> coada;
        for (int i = 1; i <= nrNoduri; i++)
            if (grad_intern[i] <= 5)
            {
                coada.push(i);
                vizitat[i] = true;
            }
        stack<int> stiva;
        while (!coada.empty())
        {
            int nod = coada.front();
            coada.pop();
            stiva.push(nod);
            for (auto vecin : lista_adiacenta[nod])
            {
                grad_intern[vecin.nod] -= 1;
                grad_extern[vecin.nod] -= 1;
                if (grad_intern[vecin.nod] <= 5 && vizitat[vecin.nod] == false)
                {
                    vizitat[vecin.nod] = true;
                    coada.push(vecin.nod);
                }
            }
        }
        vector<int> sortare;
        while (!stiva.empty())
        {
            sortare.push_back(stiva.top());
            stiva.pop();
        }
        for (auto nod : sortare)
            cout << nod << " "; // ordinea in care le coloram cu una dintre cele 6 culori nefolosita de vecin
    }

    Graf transpunere()
    {
        Graf t(nrNoduri, nrMuchii);
        for (auto muchie : muchii)
        {
            int x = muchie.x, y = muchie.y, cost = muchie.cost;
            t.muchii.push_back(Muchie(y, x, cost));
            t.lista_adiacenta[y].push_back(Nod(x, cost));
        }
        return t;
    }

    int lantHamiltonianCostMinim()
    {

        vector<vector<int>> drumuri;
        vector<vector<int>> pred;
        FloydWarshall(drumuri, pred);
        int nrsubm = 1 << nrNoduri;
        vector<vector<int>> dp(nrNoduri, vector<int>(nrsubm, infinity));
        for (int i = 0; i < nrNoduri; i++)
            dp[i][1 << i] = 0;
        // dp[0][1] = 0;

        for (int s = 0; s < nrsubm; s++)
        {
            for (int i = 0; i < nrNoduri; i++)
            {
                int nod = i + 1;
                if (s & (1 << i))
                {
                    for (int j = 0; j < nrNoduri; j++)
                    // for (auto vecin : lista_adiacenta[nod])
                    {
                        // int j = vecin.nod - 1;
                        if (j != i && ((s & (1 << j)) != 0) && dp[j][s ^ (1 << i)] != infinity) //
                        {
                            // dp[i][s] = true;

                            int cost = drumuri[j + 1][i + 1];
                            // int cost = 0;
                            if (dp[i][s] > dp[j][s ^ (1 << i)] + cost)
                            {
                                // if (drumuri[j + 1][i + 1] != 0) // daca exista de la j+1 la i+1
                                dp[i][s] = dp[j][s ^ (1 << i)] + drumuri[i + 1][j + 1];
                            }
                        }
                    }
                }
            }
        }
        int minim = infinity;
        for (int i = 0; i < nrNoduri; i++)
        {
            // if (dp[i][nrsubm - 1] == true)
            // return 1;
            minim = min(minim, dp[i][nrsubm - 1]);
        }
        for (int i = 0; i < nrNoduri; i++)
        {
            for (int j = 0; j < nrsubm; j++)
                if (dp[i][j] != infinity)
                    cout << dp[i][j] << " ";
                else
                    cout << -1 << " ";
            cout << endl;
        }
        return (minim == infinity) ? -1 : minim;
    }

    // Kosaraju
    void componenteTareConexe()
    {
        stack<int> stiva;
        Graf transpus = transpunere();
        for (int i = 1; i <= nrNoduri; i++)
            vizitat[i] = false;
        for (int i = 1; i <= nrNoduri; i++)
            if (vizitat[i] == false)
                dfs(i, stiva);
        for (int i = 1; i <= nrNoduri; i++)
            vizitat[i] = false;

        while (!stiva.empty())
        {
            int nod = stiva.top();
            stiva.pop();
            stack<int> stivaTranspus;

            if (transpus.vizitat[nod] == false)
            {
                transpus.dfs(nod, stivaTranspus);
                while (!stivaTranspus.empty())
                {
                    cout << stivaTranspus.top() << " ";
                    stivaTranspus.pop();
                }
                cout << endl;
            }
        }
    }
};

// bipartit ++ daca e atribuie culori
void dfs2(int start, int culoare, vector<int> &culori, vector<bool> &vizitat, vector<vector<int>> ma, bool &bipartit)
{
    vizitat[start] = true;
    culori[start] = culoare;
    for (int vecin = 1; vecin < ma[start].size(); vecin++)
    {
        if (ma[start][vecin] == 1)
        {
            if (vizitat[vecin] == false)
            {
                dfs2(vecin, 1 - culoare, culori, vizitat, ma, bipartit);
            }
            else
            {
                if (culori[vecin] == culori[start])
                {
                    bipartit = false;
                }
            }
        }
    }
}

bool bipartit(vector<vector<int>> ma, int n, vector<int> &culori)
{
    vector<bool> vizitat(n + 1, false);
    bool bipartit = true;
    dfs2(1, 0, culori, vizitat, ma, bipartit);
    return bipartit;
}

// muchii da sau nu in apcm
void dfsApcm(int start, int level, vector<bool> &vizitat, vector<int> &nivel, vector<int> &cost, vector<int> &tata, vector<vector<Nod>> &apcm)
{
    vizitat[start] = true;
    nivel[start] = level;
    // cout << start << " ";
    for (auto muchie : apcm[start])
    {
        if (vizitat[muchie.nod] == false)
        {
            tata[muchie.nod] = start;
            cost[muchie.nod] = muchie.cost;
            dfsApcm(muchie.nod, level + 1, vizitat, nivel, cost, tata, apcm);
        }
    }
}

int get_radacina(int x, vector<int> &tata)
{
    while (tata[x] > 0)
        x = tata[x];
    return x;
}

int intersectie(int x, int y, vector<int> &tata, vector<int> &nivel, vector<int> &cost)
{
    int maxim = 0;
    if (nivel[x] > nivel[y])
        swap(x, y);
    while (nivel[x] < nivel[y])
    {
        maxim = max(maxim, cost[y]);
        y = tata[y];
    }
    while (x != y)
    {
        maxim = max(maxim, max(cost[x], cost[y]));
        x = tata[x];
        y = tata[y];
    }
    return maxim;
}

void interogariAPCM()
{
    int n, m;
    cin >> n >> m;
    Graf g(n, m);
    vector<Muchie> aux;
    for (int i = 1; i <= m; i++)
    {
        int x, y, c;
        cin >> x >> y >> c;
        g.lista_adiacenta[x].push_back(Nod(y, c));
        g.lista_adiacenta[y].push_back(Nod(x, c));
        g.muchii.push_back(Muchie(x, y, c));
    }
    aux = g.muchii;
    vector<Muchie> apcm;
    vector<vector<Nod>> apcmLa;
    vector<int> tata;
    g.Kruskal(apcm, apcmLa, tata);

    vector<int> nivel(g.nrNoduri + 1, 0);
    vector<int> cost(g.nrNoduri + 1, 0);

    int radacina = get_radacina(1, tata);

    // for (int i = 1; i <= n; i++)
    // {
    //     cout << i << ": ";
    //     for (auto v : apcmLa[i])
    //         cout << v.nod << " ";
    //     cout << endl;
    // }

    vector<bool> vizitat(g.nrNoduri + 1, false);
    dfsApcm(radacina, 1, vizitat, nivel, cost, tata, apcmLa);

    int q;
    cin >> q;
    for (int i = 1; i <= q; i++)
    {
        int poz;
        cin >> poz;
        Muchie muchie = aux[poz - 1];
        if (muchie.cost == intersectie(muchie.x, muchie.y, tata, nivel, cost))
            cout << "Da\n";
        else
            cout << "Nu\n";
        // cout << muchie.x << " " << muchie.y << "(" << muchie.cost << ")";
        // cout << ": " << getMaximCostIntersection(muchie.x, muchie.y, tata, nivel, cost);
        // cout << endl;
    }
}

// ciclu eulerian
void euler(int v, Graf &g, vector<int> &ciclu)
{
    while (g.grad_intern[v] > 0)
    {
        int vecin = g.lista_adiacenta[v][0].nod;
        g.removeMuchie(v, vecin);
        euler(vecin, g, ciclu);
    }
    ciclu.push_back(v);
}
void cicluEulerian(int v, Graf g)
{
    g.calculeazaGrad();
    vector<int> ciclu;
    euler(1, g, ciclu);
    for (auto c : ciclu)
        cout << c << " ";
}

// flux edmond karp

bool bfsFlux(vector<vector<int>> &grafRezidual, vector<int> &tata, int start, int end)
{
    int n = grafRezidual.size() - 1;
    vector<bool> vizitat(n + 1, false);
    queue<int> coada;

    coada.push(start);
    vizitat[start] = true;
    tata[start] = -1;
    while (!coada.empty())
    {
        int nod = coada.front();
        coada.pop();

        for (int vecin = 1; vecin <= n; vecin++)
        {
            if (vizitat[vecin] == false && grafRezidual[nod][vecin] > 0)
            {

                coada.push(vecin);
                tata[vecin] = nod;
                vizitat[vecin] = true;

                if (vecin == end)
                    return true;
            }
        }
    }
    return false;
}

void dfs(int start, vector<vector<int>> graf, vector<bool> &vizitat)
{
    // cout << start << " ";
    vizitat[start] = true;
    int n = graf.size() - 1;
    // cout << n;
    for (int i = 1; i <= n; i++)
    {
        if (vizitat[i] == false && graf[start][i] > 0)
        {
            dfs(i, graf, vizitat);
        }
    }
}

// pt flux maxim cost minim putem pune muchia respectiva din graful rezidual va avea costul -cost ( unde cost = costul muchiei in graful normal)
// apoi la fiecare pas din edmondsKarp determinam lantul rezidual de cost minim folosind bellman ford => ok
int edmondsKarp(int start, int end, vector<vector<int>> capacitate, vector<vector<int>> &flux, vector<bool> &taietura)
{
    int n = capacitate.size() - 1;
    vector<vector<int>> grafRezidual = capacitate;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            grafRezidual[i][j] -= flux[i][j];
            grafRezidual[j][i] += flux[i][j];
        }
    }

    vector<int> tata(n + 1);

    while (bfsFlux(grafRezidual, tata, start, end))
    {
        int fluxRez = infinity;
        for (int nod = end; nod != start; nod = tata[nod])
        {
            // tata[nod] -> nod
            fluxRez = min(fluxRez, grafRezidual[tata[nod]][nod]);
        }
        for (int nod = end; nod != start; nod = tata[nod])
        {
            // tata[nod] -> nod
            grafRezidual[tata[nod]][nod] -= fluxRez;
            grafRezidual[nod][tata[nod]] += fluxRez;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (capacitate[i][j] >= 0)
                flux[i][j] = capacitate[i][j] - grafRezidual[i][j];
            else
                flux[i][j] = 0;
        }
    }
    taietura.resize(n + 1);
    for (int i = 0; i < taietura.size(); i++)
        taietura[i] = false;

    dfs(start, grafRezidual, taietura);
    int fmax = 0;
    // for (int i = 0; i < taietura.size(); i++)
    //     cout << taietura[i] << " ";
    // cout << endl;
    for (int i = 1; i <= n; i++)
        fmax += flux[start][i];
    return fmax;
}

// dist levensthein - pt clustering in k facem Kruskal pana la n-k cu costul
// distanta levenshtein

int levenshteinDist(string cuv1, string cuv2)
{
    int n = cuv1.length();
    int m = cuv2.length();
    int c[n + 1][m + 1];
    c[0][0] = 0;
    for (int i = 1; i <= n; i++)
        c[i][0] = i;
    for (int i = 1; i <= m; i++)
        c[0][i] = i;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (cuv1[i - 1] == cuv2[j - 1])
                c[i][j] = c[i - 1][j - 1];
            else
            {
                c[i][j] = 1 + min(c[i - 1][j], min(c[i - 1][j - 1], c[i][j - 1]));
            }
        }
    }

    // for (auto it : listaMuchii)
    // {

    //     if (Repr(it.x, tata) != Repr(it.y, tata))
    //     {

    //         solutie.push_back(it);
    //         Union(it.x, it.y, n, tata, h);
    //         nrmsel += 1;
    //         if (nrmsel == n - k)
    //             break;
    //     }
    // }
    // for (int i = 1; i <= n; i++)
    // {
    //     cout << noduri[i].s << " " << Repr(i, tata) << endl; -> s reprezinta string ( salvez nodurile cu string pentru a le putea afisa )
    // }
    // gradul de separare este costul urmatoarei muchii pe care am fi ales-o
    return c[n][m];
}

int main()
{
    int n, m, k;
    in >> n >> m >> k;
    int start = n + 1;
    n++;
    // nodul n+1 e sursa imaginara
    Graf g(n, m);
    for (int i = 1; i <= k; i++)
    {
        int nod;
        in >> nod;
        g.lista_adiacenta[start].push_back(Nod(nod, 1));
        g.muchii.push_back(Muchie(start, nod, 1));
    }
    for (int i = 1; i <= m; i++)
    {
        int x, y;
        in >> x >> y;
        g.lista_adiacenta[x].push_back(Nod(y, 1));
        // g.lista_adiacenta[y].push_back(Nod(x, 1));
        g.muchii.push_back(Muchie(x, y, 1));
    }
    vector<int> tata;
    vector<int> drum;
    g.calculeazaGrad();
    g.DagDrumMaxim(start, drum, tata);
    int imx = 1;
    for (int i = 2; i <= n; i++)
        if (drum[imx] < drum[i])
            imx = i;
    cout << drum[imx] - 1 << endl;
    vector<int> d;
    while (tata[imx] != 0)
    {
        d.push_back(imx);
        imx = tata[imx];
    }
    for (int i = d.size() - 1; i >= 0; i--)
        cout << d[i] << " ";
    return 0;
}