#include <limits.h>
#include <stdio.h>
#include <vector>
#include <queue>
using std::priority_queue;
using std::vector;
#define Smerenie 20000
#define Nadejde 2000
#define MAX_K 15
typedef struct {
int u, cost;
} pair;
typedef struct {
int v, cost, next;
} list;
typedef struct {
bool operator()(const pair &X, const pair &Y) {
return (X.cost > Y.cost);
}
} minHeap;
int N, M, K;
int shl[MAX_K];
int take[MAX_K];
int bits[MAX_K];
int adj[Nadejde + 1];
list l[Smerenie + 1];
int lg[(1 << MAX_K) + 1];
int d[MAX_K][(1 << MAX_K) + 1];
int dist[Nadejde + 1][Nadejde + 1];
priority_queue <pair, vector<pair>, minHeap> heap;
/** min(X, Y). **/
int MIN(int X, int Y) {
return X < Y ? X : Y;
}
void addEdge(int u, int v, int cost, int pos) {
l[pos].v = v;
l[pos].cost = cost;
l[pos].next = adj[u];
adj[u] = pos;
}
/** Initializeaza "dist". **/
void init(int u) {
int i;
for (i = 1; i <= N; i++) {
dist[u][i] = INT_MAX;
}
}
/** Adauga in heap nodul "u". **/
void enqueue(int u, int source, int cost) {
dist[source][u] = cost;
heap.push({u, cost});
}
/** Da-mi urmatorul nod. **/
void dequeue(int *u, int *cost) {
pair top = heap.top();
(*u) = top.u;
(*cost) = top.cost;
heap.pop();
}
/** Calculeaza pentru fiecare nod distanta pana la nodul "source". **/
void dijkstra(int source) {
int u, v, pos, cost, curr;
init(source);
enqueue(source, source, 0);
while (!heap.empty()) {
dequeue(&u, &cost);
if (cost == dist[source][u]) {
for (pos = adj[u]; pos; pos = l[pos].next) {
v = l[pos].v;
curr = cost + l[pos].cost;
if (curr < dist[source][v]) {
enqueue(v, source, curr);
}
}
}
}
}
/** Analizeaza submultimea "set". **/
void analyzes(int set) {
int i, j, save, last, size = 0;
if (set & (set - 1)) {
for (save = set; save; save ^= last) {
last = save & -save;
bits[size++] = lg[last];
}
for (i = 0; i < size; i++) {
d[bits[i]][set] = INT_MAX;
for (j = 0; j < size; j++) {
if (i != j) {
d[bits[i]][set] = MIN(d[bits[i]][set], d[bits[j]][set ^ shl[bits[i]]] + dist[take[bits[i]]][take[bits[j]]]);
}
}
}
}
}
int main(void) {
int i, u, v, cost;
FILE *f = fopen("ubuntzei.in", "r");
/* Citirea datelor. */
fscanf(f, "%d %d %d", &N, &M, &K);
for (i = 0; i < K; i++) {
fscanf(f, "%d", &take[i]);
}
for (i = 1; i <= M; i++) {
fscanf(f, "%d %d %d", &u, &v, &cost);
addEdge(u, v, cost, i);
addEdge(v, u, cost, i + M);
}
fclose(f);
/* Construieste "dist". **/
dijkstra(1);
for (i = 0; i < K; i++) {
dijkstra(take[i]);
}
/* Initilizarea dinamicii. */
for (i = 0; i < K; i++) {
shl[i] = 1 << i;
d[i][shl[i]] = dist[1][take[i]];
lg[shl[i]] = i;
}
/* Treci prin submultimi. */
//fprintf(stderr, "...");
int total = (1 << K) - 1;
for (i = 1; i <= total; i++) {
analyzes(i);
}
/*
for (register int u = 1; u <= N; u++) {
fprintf(stderr, "Nodul %d: ", u);
for (register int v = 1; v <= N; v++) {
fprintf(stderr, "(%d, %d), ", v, dist[u][v]);
}
fprintf(stderr, "\n");
}
*/
/* Calcularea solutiei. */
int min = INT_MAX;
if (K == 0) {
min = dist[1][N];
} else for (i = 0; i < K; i++) {
min = MIN(min, d[i][total] + dist[take[i]][N]);
}
/* Afisarea solutiei. */
freopen("ubuntzei.out", "w", stdout);
fprintf(stdout, "%d\n", min);
fclose(stdout);
/// Multumim Doamne!
puts("Doamne ajuta!");
return 0;
}