Cod sursa(job #2148564)

Utilizator NannyiMaslinca Alecsandru Mihai Nannyi Data 1 martie 2018 19:58:08
Problema Ubuntzei Scor 70
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.38 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;

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

#define inf 210005
#define nmax 2005

int n,m,k,u[17],dist[17][nmax],total,dp[1<<17][17],bitmx;
bool viz[nmax][nmax];

struct str
{
    int vecin,cost;
    bool operator <(const str &other)const
    {
        return cost<other.cost;
    }
};

vector<str>Q[nmax];
priority_queue<str>que;


void read()
{
    f>>n>>m>>k;
    for (int i=1; i<=k; ++i)
        f>>u[i];
    for (int i=1; i<=m; ++i)
    {
        int e1,e2,e3;
        f>>e1>>e2>>e3;
        Q[e1].push_back({e2,e3});
        Q[e2].push_back({e1,e3});
    }
    memset(dist,inf,sizeof(dist));
}

void Dijkstra(int nod)
{
    dist[nod][u[nod]]=0;
    que.push({u[nod],0});
    while (!que.empty())
    {
        int cnod=que.top().vecin;
        int ccost=que.top().cost;
        que.pop();
        if (dist[nod][cnod]>ccost)
            continue;
        for (auto w:Q[cnod])
        {
            if (ccost+w.cost<dist[nod][w.vecin])
            {
                dist[nod][w.vecin]=ccost+w.cost;
                que.push({w.vecin,dist[nod][w.vecin]});
            }
        }
    }
}

void solve2()
{
    bitmx=(1<<k)-1;
    memset(dp,inf,sizeof(dp));
    for (int i=0; (1<<i)<bitmx; ++i)
        dp[1<<i][i+1]=dist[i+1][1];

    // cost[i][j] <=> costul drumului care porneste din localitatea u[i] pana la localitatea j
    // dp[i][j] <=> costul pentru a intra in configuratia i cu ultima localitate j

    // ca sa ajungi in configuratia unde bitul x == true (<=> am folosit localitatea u[x]),
    // vom lua toate configuratiile asemanatoare, doar cu un bit fals in loc de true
    // (adica am folosit cu o localitate mai putin) si vom updata costul

    for (int i=1; i<=bitmx; ++i)
        for (int j=0; j<k; ++j)
            if (i&(1<<j))
            {
                int mask=i-(1<<j); //practic daca bitul j+1 e adevarat, il facem fals
                for (int q=0; q<k; ++q)
                {
                    if (mask&(1<<q))
                    {
                        dp[i][j+1]=min(dp[i][j+1],dp[mask][q+1]+dist[j+1][u[q+1]]);
                    }
                    // practic aici am luat mastile care au avut bitul q+1 true,
                    // astfel dp[mask][q+1] reprezinta configuratia mask care s a terminat
                    // in localitatea u[q+1]. evident, daca masca are bitul q+1 negativ,
                    // nu are cum sa se termine in localitatea u[q+1]

                    // astfel costul pentru a ajunge in configuratia i cu ultima localitate (j+1)
                    // este costul pentru a ajunge in configuratia mask cu ultima localitate (q+1) +
                    // + costul drumului care porneste in localitatea j+1, pana la localitatea (q+1)

                }
            }
}
void solve()
{
    if (k==0)
    {
        u[1]=1;
        Dijkstra(1);
        g<<dist[1][n];
        return;
    }
    else if (k==1)
    {
        Dijkstra(1);
        g<<dist[1][n]+dist[1][1];
        return;
    }
    for (int i=1; i<=k; ++i)
        Dijkstra(i);
    total=inf;
    solve2();
    for (int i=0; i<k; ++i)
        total=min(total,dp[bitmx][i+1]+dist[i+1][n]);
    g<<total;
}


int main()
{
    read();
    solve();
    return 0;
}