Cod sursa(job #1965430)

Utilizator BugirosRobert Bugiros Data 14 aprilie 2017 13:29:40
Problema Gather Scor 70
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.37 kb
#include <fstream>
#include <queue>
#include <vector>
using namespace std;

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

const int MAXN = 751;
const int MAXK = 16;
const long long INF = 1ll << 50;

int n,k;

struct muchie
{
    int vecin;
    int cost;
    int capacitate;
};

vector<muchie> vecini[MAXN];

int detinut[MAXK];

void citire()
{
    int m;
    in >> k >> n >> m;
    for (int i = 1;i <= k;++i)
    {
        in >> detinut[i];
        --detinut[i];//numerotam de la zero
    }

    for (int i = 1;i <= m;++i)
    {
        int a,b,c,d;
        in >> a >> b >> c >> d;
        vecini[a - 1].push_back((muchie){b - 1,c,d});
        vecini[b - 1].push_back((muchie){a - 1,c,d});
    }
}


//d[i][j][k] - costul minim de a ajunge la nodul k, plecand de la detinutul i
//             folosind doar muchii cu cost mai mare sau egal cu j
long long d[MAXK][MAXK][MAXN];

//a[i][j] - costul minim de a ajunge la nodul j, avand ca detinuti ce ne urmaresc
//          valorile de 1 din reprezentarea binara a lui i
long long a[1 << MAXK][MAXN];


int nrbiti(int x)
{
    int rasp = 0;
    while(x != 0)
    {
        rasp += x & 1;//adunam zero daca nu are bitul 1, adunam 1 altfel
        x >>= 1;
    }
    return rasp;
}

struct nod_dijk
{
    int nod;
    long long dist;
    bool operator < (const nod_dijk &b) const
    {
        return dist > b.dist;//heap implicit de maxime
    }
};

void dijkstra(int sursa, int nrdetinuti, long long D[])
{
    priority_queue<nod_dijk> heap;
    for (int i = 0;i <= n;++i)
        D[i] = INF;
    D[sursa] = 0;
    heap.push((nod_dijk){sursa, 0});
    while(!heap.empty())
    {
        int nod = heap.top().nod;
        int dist = heap.top().dist;
        heap.pop();
        if (dist > D[nod])
            continue;
        for (unsigned int i = 0;i < vecini[nod].size();++i)
        {
            int vecin = vecini[nod][i].vecin;
            int cost = vecini[nod][i].cost;
            int capacitate = vecini[nod][i].capacitate;
            if (capacitate >= nrdetinuti &&
                D[vecin] > D[nod] + cost)
            {
                D[vecin] = D[nod] + cost;
                heap.push((nod_dijk){vecin, D[vecin]});
            }
        }
    }
    for (int i = 1;i <= n;++i)
        if (D[i] < INF)
            D[i] *= nrdetinuti + 1;//intra si Gigel aici la cost
}

void prelucrare()
{
    for (int j = 0;j <= k + 1;++j)
        dijkstra(0, j, d[0][j]);//nodul lui Gigel este zero.

    for (int i = 1;i <= k;++i)
        for (int j = 0;j <= k + 1;++j)
            dijkstra(detinut[i], j, d[i][j]);




    for (int i = 0;i < (1 << (k + 1));++i)
        for (int j = 0;j <= k;++j)
            a[i][j] = INF;

    a[1][0] = 0;

    for (int i = 2;i < (1 << (k + 1));++i)
    {
        int nrdetinuti = __builtin_popcount(i) - 2;  //nrbiti(i) - 2;
        for (int j = 0;j <= k;++j)
            if (i & (1 << j))
                for (int p = 0;p <= k;++p)
                    a[i][j] = min(a[i][j],
                                  a[i ^ (1 << j)][p] + d[p][nrdetinuti][detinut[j]]);
    }
}

void afisare()
{
    long long rasp = INF;
    for (int i = 0;i <= k;++i)
        rasp = min(rasp, a[(1 << (k + 1)) - 1][i]);
    out << rasp << '\n';
}

int main()
{
    citire();
    prelucrare();
    afisare();
    return 0;
}