Cod sursa(job #2108871)

Utilizator tanasaradutanasaradu tanasaradu Data 18 ianuarie 2018 21:35:34
Problema Ubuntzei Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.27 kb
#include <bits/stdc++.h>
using namespace std;
ifstream fin ("ubuntzei.in");
ofstream fout ("ubuntzei.out");
const short Nmax = 2001;
const int Pmax = (1 << 17) + 1;
const short Kmax = 17;
const int inf = (1 << 30);
int n, m, dp[Pmax][Kmax], k, valmax, cost[Nmax][Nmax], b[Kmax], dist[Nmax];
bitset < Nmax > viz;
vector < pair < int, int > > L[Nmax];
struct Pair
{
    int nod, val;
    bool operator < (const Pair &e) const
    {
        return val > e . val;
    }
};
priority_queue < Pair > Q;
/**
 dp[i][j] - > lungimea minima de la nodul 1 la nodul j trecand prin i valori binare
*/

inline void Read()
{
    int x, y, c;
    fin >> n >> m;
    fin >> k;
    for(int i = 1 ; i <= k ; i++)
        fin >> b[i];
    b[0] = 1;
    b[++k] = n;
    valmax = (1 << k) - 1;
    for(int i = 1 ; i <= m ; i++)
    {
        fin >> x >> y >> c;
        L[x] . push_back({ y, c });
        L[y] . push_back({ x, c });
    }
    for(int i = 0 ; i <= valmax ; i++)
        for(int j = 0 ; j <= k ; j++)
            dp[i][j] = inf;
    for(int i = 1 ; i <= n ; i++)
        for(int j = 1 ; j <= n ; j++)
            cost[i][j] = inf;
}
inline void Dijkstra(int x)
{
    int d, p;
    Pair w, w1;
    viz . reset();
    for(int i = 1 ; i <= n ; i++)
        dist[i] = inf;
    dist[x] = 0;
    w . nod = x;
    w . val = 0;
    Q . push(w);
    while(! Q .empty())
    {
        w = Q . top();
        Q . pop();
        if(!viz[w . nod])
        {
            viz[w . nod] = 1;
            for(auto c : L[w . nod])
            {
                p = c . first;
                d = c . second;
                if(dist[p] > dist[w . nod] + d)
                {
                    dist[p] = dist[w . nod] + d;
                    w1 . nod = p;
                    w1 . val = dist[p];
                    Q . push(w1);
                }
            }
        }
    }
}
inline void Build()
{
    for(int i = 0 ; i <= k ; i++)
    {
        Dijkstra(b[i]);
        for(int j = 0 ; j <= k ; j++)
            cost[i][j] = dist[b[j]];
    }

}
inline void Solve()
{
    ///Initializari
    for(int i = 0 ; i < k ; i++)
        dp[1 << i][i] = cost[1][b[i]]; /// numai bitul i este 1 inseamna ca drumul care incepe de la 1 trece numai
    /// pe la un singur prieten
    for(int i = 0 ; i <= valmax ; i++)
        for(int j = 0 ; j <= k ; j++)
            if(( i & (1 << j)))
                for(int pas = 0 ; pas <= k ; pas++)
                    if(!(i & (1 << pas)) ) /// nu am trecut pe la al pas-lea prieten
                        dp[(i | (1 << pas))][pas] = min(dp[(i | (1 << pas))][pas], dp[i][j] + cost[j][pas]);
    ///cum i are la bitul cu numarul j 1 inseamna ca i | (1 << pas) va avea la bitul cu numarul pas si el tot 1
    /// = > trecem si la nodul cu numarul pas (de la nodul cu numarul j)

    int sol = inf;
    for(int i = 0 ; i < k ; i++)
        sol = min(sol, dp[valmax][i] + cost[i][k]);
    /// dp[valmax][i] - > costul minim de la nodul cu nr 1 la nodul cu nr i trecand prin toti prietenii
    /// (inclusiv nodul 1)
    if(k == 0)
        fout << cost[1][n] << "\n";
    else
        fout << sol << "\n";


}
int main()
{
    Read();
    Build();
    Solve();
    fin.close();
    fout.close();
    return 0;
}