Cod sursa(job #2650526)

Utilizator IRadu1529Radu Ionescu IRadu1529 Data 19 septembrie 2020 11:40:21
Problema Stramosi Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 6.45 kb
#include<iostream>
#include<vector>
#include<fstream>
#include <queue>

using namespace std;

ifstream fin("cezar.in");

ofstream fout("cezar.out");

int n, k, sediu, scadere, conditie = 0;

vector<int> auxEliminare;

vector<int> elimCoada;

struct muchie
{

    int val, origine, nrMuchii;

    muchie(int val, int origine, int nrMuchii)
        : val(val), origine(origine), nrMuchii(nrMuchii)
    {
    }
};

struct comp
{
    bool operator()(muchie const& p1, muchie const& p2)
    {
        return p1.nrMuchii < p2.nrMuchii;
    }

};

void GasireSediu(vector<int>& origine, vector<vector<int> > liste, vector<int> grad, int GradMax, vector<int>& coada, vector<int>& StocareNoduri)
{
    while (GradMax > 1)
    {
        GradMax = 0;

        for (int i = 0; i < coada.size(); i++)
            if (grad[coada[i]] == 1)
            {
                int primElLista = liste[coada[i]][0], el = coada[i], gra = grad[el], aux;

                auxEliminare.push_back(primElLista);

                origine[el] = primElLista;

                grad[el] = 0;

                StocareNoduri[primElLista] += StocareNoduri[el] + 1;

                for (int j = 0; j < liste[primElLista].size(); j++)
                    if (liste[primElLista][j] == el)
                    {
                        liste[primElLista].erase(liste[primElLista].begin() + j);

                        break;
                    }


                aux = StocareNoduri[primElLista];///afisare doar

                elimCoada.push_back(i);
            }

        for (int i = auxEliminare.size() - 1; i >= 0; i--)///scad gradul dupa ce am parcurs elementele
        {
            int g = auxEliminare[i], h = grad[auxEliminare[i]];

            grad[auxEliminare[i]]--;

            h = grad[auxEliminare[i]];

            auxEliminare.pop_back();
        }

        for (int i = elimCoada.size() - 1; i >= 0; i--)///elimin el cu grad 1
        {
            int ui = coada[elimCoada[i]], jj = elimCoada[i];

            coada.erase(coada.begin() + elimCoada[i]);

            ui = coada[elimCoada[i]];

            elimCoada.pop_back();
        }

        for (int i = 0; i < coada.size(); i++)///recalculez gradul maxim
            if (grad[coada[i]] > GradMax)
                GradMax = grad[coada[i]];
    }

    GradMax = 0;

    if (coada.size() == 1)
        sediu = coada.back();

    else
        for (int i = 0; i < coada.size(); i++)
            if (StocareNoduri[coada[i]] > GradMax)
            {
                GradMax = StocareNoduri[coada[i]];

                origine[coada[i]] = liste[coada[i]][0];

                sediu = coada[i];
            }
}

int verificare(int el, int l, vector<int> origine, vector<vector<int> > mat)
{
    for (int i = 0; i < mat[l].size(); i++)
        if (mat[l][i] == origine[el] || origine[mat[l][i]] == el)
            return 1;


    return 0;
}

void afisare(vector<int> sumaSirt, int nrSiruri)
{
    for (int i = 1; i <= nrSiruri; i++)
        cout << sumaSirt[i] << "\n";
    cout << "-----------------------------------------------\n";
}

void adaugare(vector<int> origine, priority_queue<muchie, vector<muchie>, comp> pCoada)
{
    vector<vector<int> > mat(n + 1, vector<int>());

    vector<int> sumaSir(n + 1, -1);

    int nrSiruri = 0, Smax = 0, maxim = 0;

    muchie el = pCoada.top();

    pCoada.pop();

    mat[1].push_back(el.val);

    sumaSir[1] = 0;

    nrSiruri++;

    while (!pCoada.empty())
    {
        //afisare(sumaSir, nrSiruri);

        Smax = -1;

        maxim = 0;

        el = pCoada.top();

        if (el.nrMuchii == 0 && conditie == 1)
            break;

        pCoada.pop();

        for (int i = 1; i <= nrSiruri; i++)
            if (mat[i].size() <= k && Smax < sumaSir[i] && verificare(el.val, i, origine, mat))
            {
                maxim = i;

                Smax = sumaSir[i];
            }

        if (maxim != 0)
        {
            nrSiruri++;

            mat[maxim].push_back(el.val);

            sumaSir[nrSiruri] = sumaSir[maxim];

            sumaSir[maxim] += el.nrMuchii + 1;///+1 pt ca profita si nodul curent, nu doar cele din subordinea lui

            if (sumaSir[maxim] > scadere)
                scadere = sumaSir[maxim];

            for (int i = 0; i < mat[maxim].size() - 1; i++)
                mat[nrSiruri].push_back(mat[maxim][i]);
        }

        if (maxim == 0)
        {
            nrSiruri++;

            mat[nrSiruri].push_back(el.val);

            if (el.val != sediu)
                sumaSir[nrSiruri] = el.val + 1;

            else
                sumaSir[nrSiruri] = 0;
        }

        if (mat[maxim].size() == k + 1)
            conditie = 1;

        //afisare(sumaSir, nrSiruri);
    }
}

void dikstra(vector<vector<int> >& liste)
{
    queue<int>drum;

    vector<int> distanta(n + 1, 2147483646);

    distanta[sediu] = 0;

    drum.push(sediu);

    while (!drum.empty())
    {
        int top = drum.front();

        for (int i = 0; i < liste[top].size(); i++)
            if (distanta[liste[top][i]] > distanta[top] + 1)
            {
                distanta[liste[top][i]] = distanta[top] + 1;

                drum.push(liste[top][i]);
            }

        drum.pop();
    }

    int S = 0;

    for (int i = 1; i <= n; i++)
        if (distanta[i] != 2147483646)
            S += distanta[i];

    fout << S - scadere;
}

int main()
{
    fin >> n >> k;

    int a, b, GradMax = 0;

    vector<int> grad(n + 1, 0);

    vector<int> StocareNoduri(n + 1, 0);

    vector<int> origine(n + 1, 0);

    vector<int> vecinSediu(n + 1, 0);

    vector<int> coada(n);

    for (int i = 0; i < n; i++)
        coada[i] = i + 1;

    vector<vector<int> > liste(n + 1, vector<int>());

    while (fin >> a >> b)
    {
        liste[a].push_back(b);

        liste[b].push_back(a);

        grad[a]++;

        grad[b]++;

        if (grad[a] > GradMax || grad[b] > GradMax)
            GradMax = max(grad[b], grad[a]);
    }

    GasireSediu(origine, liste, grad, GradMax, coada, StocareNoduri);

    priority_queue<muchie, vector<muchie>, comp> pCoada;

    for (int i = 1; i <= n; i++)
    {
        muchie x(i, origine[i], StocareNoduri[i]);

        pCoada.push(x);
    }

    adaugare(origine, pCoada);

    //cout << "sediu " << sediu << "\n";

    dikstra(liste);
}