Cod sursa(job #2308707)

Utilizator borcanirobertBorcani Robert borcanirobert Data 27 decembrie 2018 17:13:11
Problema Ubuntzei Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.2 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
using namespace std;

ifstream fin("ubuntzei.in");
ofstream fout("ubuntzei.out");

const int Inf = 0x3f3f3f3f;

using VI = vector<int>;
using VP = vector<pair<int, int>>;

struct Pair{
    int node, cost;

    bool operator < (const Pair& p) const
    {
        return cost > p.cost;
    }
};

int N, M, K;
VI a;                       // a - lista nodurilor care trebuie vizitate
vector<VP> G;               // G - graful dat
vector<VI> cost;            // cost[i][j] = costul dintre a[i] si a[j]
vector<VI> D;               // D[mask][i] = costul minim daca merg prin nodurile din mask, ultimul nod vizitat fiind i
priority_queue<Pair> Q;

void ReadData();
void Solve();
void Dyn();
VI Dijkstra(int node);      // returneaza un vector reprezentand costurile de la nodul node la oricare alt nod

int main()
{
    ReadData();
    Solve();

    fout << D[(1 << (K - 1)) - 1][K - 1] << '\n';

    fin.close();
    fout.close();
    return 0;
}

void ReadData()
{
    fin >> N >> M;

    fin >> K;
    a = VI(K + 2); ++K;
    a[0] = 1;
    for (int i = 1; i < K; ++i)
        fin >> a[i];
    a[K++] = N;

    G = vector<VP>(N + 1);
    int x, y, z;
    while (M--)
    {
        fin >> x >> y >> z;

        G[x].push_back({y, z});
        G[y].push_back({x, z});
    }
}

void Solve()
{
    D = vector<VI>(1 << (K - 1), VI(K, Inf));
    cost = vector<VI>(K, VI(K));

    for (size_t i = 0; i < a.size() - 1; ++i)
    {
        VI c = Dijkstra(a[i]);

        for (size_t j = i + 1; j < a.size(); ++j)
        {
            cost[i][j] = cost[j][i] = c[a[j]];

          //  cout << a[i] << ' ' << a[j] << ' ' << cost[i][j]; cin.get();
        }
    }

    Dyn();
}

void Dyn()
{
    D[0][0] = 0;
    for (int mask = 1; mask < (1 << (K - 1)); ++mask)       // pentru fiecare masca de biti posibila
        for (int i = 1; i < K; ++i)                         // ultimul nod vizitat poate fi doar intre 1 si K ( daca era 0 e cazul initial )
        {
            if ( !(mask & (1 << (i - 1))) )                 // nodul i trebuie sa fie in masca
                continue;

            if ( !(mask ^ (1 << (i - 1))) )                       // daca i e chiar primul nod vizitat
            {
                D[mask][i] = cost[0][i];
                continue;
            }

            for (int j = 1; j < K; ++j)                     // caut penultimul posibil nod vizitat
            {
                if ( !(mask & (1 << (j - 1))) )
                    continue;

                D[mask][i] = min(D[mask][i], D[mask ^ (1 << (i - 1))][j] + cost[i][j]);     // si calculez in fuctie de el
            }
        }
}

VI Dijkstra(int node)       // Dijkstra clasic cu priority_queue
{
    Q.push({node, 0});
    VI c(N + 1, Inf);
    c[node] = 0;

    while (!Q.empty())
    {
        int node = Q.top().node;
        int cc = Q.top().cost;
        Q.pop();

        if ( cc != c[node] )
            continue;

        for (const auto& x : G[node])
        {
            int next = x.first;
            int cost = x.second;

            if ( c[next] > c[node] + cost )
            {
                c[next] = c[node] + cost;
                Q.push({next, c[next]});
            }
        }
    }

    return c;
}