Cod sursa(job #653404)

Utilizator wefgefAndrei Grigorean wefgef Data 27 decembrie 2011 21:33:11
Problema Ubuntzei Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.44 kb
#include <cassert>
#include <cstdio>
#include <cstring>

#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

#define FORIT(it, v) for (typeof((v).begin()) it = (v).begin(); it != (v).end(); ++it)
#define x first
#define y second

const int MAX_N = 2048;
const int MAX_K = 17;
const int INF = 0x3f3f3f3f;

int n, m, k;
int c[MAX_K];
vector< pair<int, int> > graph[MAX_N];
int dist[MAX_N];
int dmin[MAX_K][MAX_K];
int d[MAX_K][1 << MAX_K];

void dijkstra(int start) {
    memset(dist, INF, sizeof(dist));

    priority_queue< pair<int, int>, vector< pair<int, int> >, greater< pair<int, int> > > heap;
    heap.push(make_pair(0, start));

    while (!heap.empty()) {
        pair<int, int> p = heap.top();
        heap.pop();

        if (dist[p.y] != INF) continue;
        dist[p.y] = p.x;

        FORIT(it, graph[p.y])
            if (dist[it->x] == INF)
                heap.push(make_pair(p.x + it->y, it->x));
    }
}

inline int bit_count(int x) {
    return !x ? 0 : 1 + bit_count(x & (x - 1));
}

int main() {
    // read
    assert(freopen("ubuntzei.in", "r", stdin));
    assert(freopen("ubuntzei.out", "w", stdout));

    assert(scanf("%d %d", &n, &m) == 2);

    assert(scanf("%d", &k) == 1);
    for (int i = 1; i <= k; ++i)
        assert(scanf("%d", &c[i]) == 1);
    c[0] = 1; c[k + 1] = n;

    for (int i = 0; i < m; ++i) {
        int a, b, cost;
        assert(scanf("%d %d %d", &a, &b, &cost) == 3);
        graph[a].push_back(make_pair(b, cost));
        graph[b].push_back(make_pair(a, cost));
    }

    // min distances
    for (int i = 0; i <= k + 1; ++i) {
        dijkstra(c[i]);
        for (int j = 0; j <= k + 1; ++j)
            dmin[i][j] = dist[c[j]];
    }

    // hamiltonian path
    memset(d, INF, sizeof(d));
    for (int conf = 1; conf < (1 << k); ++conf) 
        for (int last = 0; last < k; ++last) {
            if (((conf >> last) & 1) == 0) continue;
      
            if (bit_count(conf) == 1) {
                d[last][conf] = dmin[0][last + 1];
                continue;
            }

            for (int new_last = 0; new_last < k; ++new_last)
                if ((conf >> new_last) & 1)
                    d[last][conf] = min(d[last][conf], d[new_last][conf ^ (1 << last)] + dmin[new_last + 1][last + 1]);
    }

    // print result
    int best = INF;
    for (int i = 0; i < k; ++i)
        best = min(best, d[i][(1 << k) - 1] + dmin[i + 1][k + 1]);
    if (k == 0) best = dmin[0][1];
    printf("%d\n", best);
}