Cod sursa(job #1586050)

Utilizator BugirosRobert Bugiros Data 31 ianuarie 2016 18:32:14
Problema Ubuntzei Scor 20
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.18 kb
//#define DEBUG
#include <fstream>
#include <vector>
#include <queue>
using namespace std;

const int MAXN = 2005;
const int MAXK = 17;
const int INF = 1 << 30;

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

int n;

vector<int> vecini[MAXN];
vector<int> cost[MAXN];

int special[MAXK];
int d[MAXN][MAXN];
int e[MAXK][1 << MAXK];
int k;

void citire()
{
    int m;
    in >> n >> m;
    in >> k;
    for (int i = 1;i <= k;++i)
        in >> special[k];
    for (int i = 1;i <= m;++i)
    {
        int x,y,c;
        in >> x >> y >> c;
        vecini[x].push_back(y);
        cost[x].push_back(c);

        vecini[y].push_back(x);
        cost[y].push_back(c);
    }
}

void dijkstra(int s)
{
    //initializare
    for (int i = 1;i <= n;++i)
        d[s][i] = INF;
    priority_queue< pair<int,int>,vector< pair<int,int> >, greater< pair<int,int> > > heap;
    heap.push(make_pair(0,s));
    while(!heap.empty())
    {
        int nod = heap.top().second;
        int c = heap.top().first;
        heap.pop();
        if (d[s][nod] != INF)
            continue;
        d[s][nod] = c;
        for (unsigned int i = 0;i < vecini[nod].size();++i)
            heap.push(make_pair(d[s][nod] + cost[nod][i],
                                vecini[nod][i]));
    }
}

void calculare_distante()
{
    //calculare d
    dijkstra(1);
    dijkstra(n);
    for (int i = 1;i <= k;++i)
        dijkstra(special[i]);
}

int lungsubm;
int S;

int sol[MAXK];

void prelucrare()
{
    S = 0;
    for (int i = 1;i <= lungsubm;++i)
        S = S ^ (1 << sol[i]);
    #ifdef DEBUG
    printf("%d\n",S);
    #endif // DEBUG
    for (int u = 1;u <= k;++u)
    {
        if ((S & (1 << u)) == 0)
            continue;
        for (int i = 1;i <= lungsubm;++i)
        {
            if (sol[i] == u)
                continue;
            int v = sol[i];
            int nr = e[v][S ^ (1 << u)] + d[special[v]][special[u]];
            if (e[u][S] == 0)
                e[u][S] = nr;
            else if (nr < e[u][S])
                nr = e[u][S];
        }
    }
}

void bkt(int poz)
{
    if (poz > lungsubm)
    {
        prelucrare();
        return;
    }
    for (int i = 1 + sol[poz - 1];i <= k - lungsubm + poz;++i)
    {
        sol[poz] = i;
        bkt(poz + 1);
    }
}

void dinamica()
{
    //initializare
    for (int i = 1;i <= k;++i)
        e[i][1 << i] = d[1][special[i]];

    for (lungsubm = 2;lungsubm <= k;++lungsubm)
        bkt(1);
}

void afisare()
{
    if (k == 0)
    {
        out << d[1][n] << '\n';
        return;
    }

    S = 0;
    for (int i = 1;i <= k;++i)
    {
        S <<= 1;
        S = S ^ 2;
    }
    int raspuns = INF;
    for (int u = 1;u <= k;++u)
    {
        int nr = e[u][S] + d[u][n];
        if (nr < raspuns)
            raspuns = nr;
    }
    out << raspuns << '\n';
}

int main()
{
    citire();
    calculare_distante();

    #ifdef DEBUG
    for (int i = 1;i <= n;++i)
    {
        for (int j = 1;j <= n;++j)
            printf("%d ",d[i][j]);
        printf("\n");
    }
    #endif // DEBUG

    dinamica();
    afisare();
    return 0;
}