Opis
BOI 2016
Bosses
Park
Spiral
Cities
Maze
Swap
CEOI 2017
Skierowanie dróg
Pewny zakład
Pułapka Mariusza
Budujemy mosty
Pościg Mariusza
Palindromiczny podział
BOI 2018
Miłosny wielokąt
Marsjańskie DNA
Problemy dżdżownicy
Prąd przemienny
Genetyka
Ścieżki
BOI 2019
Flash Memory
Nautilus
Alpine Valley
Tom's Kitchen
Necklace
Olympiads
BOI 2020
Kolory
Mieszanki
Joker
Graf
Wioska
Wirusy
CEOI 2020
Fajny płot
Drogi
Star Trek
Napój Wielkiej Potęgi
Wiosenne porządki
Szachowa gorączka

Cities

Dany jest ważony graf o $n$ wierzchołkach i $m$ krawędziach, przy czym $k$ wierzchołków jest wyróżnionych, a wagi krawędzi są dodatnie. Znaleźć najtańszy podgraf spójny zawierający wyróżnione wierzchołki.

Drzewo Steinera

Nietrudno się przekonać, że taki podgraf musi być drzewem (bo w przeciwnym wypadku możemy z niego usunąć krawędź leżącą na cyklu, nie psując spójności i zmniejszając wagę podgrafu). Drzewo to nazywa się w teorii grafów drzewem Steinera.

Jest to klasyczny problem, który w ogólności jest NP-zupełny, ale dla małych wartości $k$ wykładnicze algorytmy radzą sobie całkiem dobrze. W szczególności dla ograniczenia $k\leq 5$ z zadania można zaproponować całkiem prosty algorytm.

Jeśli zaznaczymy sobie w grafie drzewo Steinera, usuniemy wszystkie krawędzie do niego nienależące i scalimy niewyróżnione wierzchołki stopnia 2, to dostaniemy taki obrazek:

 1---*---*---*---5
    /    |    \
 2-/     3     \-4

Wierzchołki wyróżnione są w nim połączone ścieżkami z co najwyżej $k-2$ wierzchołkami „pomocniczymi”. Łatwo pokazać, że wierzchołki pomocnicze leżą na jednej ścieżce $p$ (zauważmy, że to nie musi być prawdą już dla $k=6$), a wszystkie pozostałe łączą się z $p$ za pomocą pojedynczych ścieżek.

Długości tych pojedynczych ścieżek łatwo znaleźć, uruchamiając algorytm Dijkstry z każdego wierzchołka wyróżnionego. To zajmie czas $O(k m \log n)$.

Pomysł jest więc taki, żeby przejść po ścieżce $p$, przy okazji „podczepiając” do niej wierzchołki wyróżnione. Będziemy iść po wirtualnym grafie, którego wierzchołki są postaci $(v,mask)$, gdzie $v$ jest wierzchołkiem oryginalego grafu, a $mask \in [0, 2^k)$ jest maską bitową, która opisuje, które wierzchołki wyróżnione już podłączyliśmy.

Na tym wirtualnym grafie też uruchamiamy algorytm Dijkstry. Zaczynamy od wszystkich wierzchołków postaci $(v,0)$, a chcemy dojść do dowolnego postaci $(v,2^k-1)$.

Krawędzie z wierzchołka $(v,mask)$ są dwojakiego rodzaju. Prowadzą do $(w,mask)$ z kosztem $c$, jeśli mieliśmy krawędź z $v$ do $w$ o koszcie $c$ w oryginalnym grafie (to odpowiada przejściu po ścieżce $p$). Lub też do $(v,mask+2^i)$ o koszcie $dist(v,i)$, jeśli $i$ jest niewybranym wierzchołkiem wyróżnionym (to odpowiada podłączeniu wierzchołka $i$). Złożoność wynosić będzie $O( (nk+m)2^k \log (n2^k) )$.

const int N = 210000, K = 5;
int n,k,m,city[K];
vector<pli> adj[N];
vector<ll> dist[K];

vector<ll> dijkstra(int n, vector<int> s, function<vector<pli>(int)> adj) {
  vector<ll> dist(n, 1e18);
  priority_queue<pli,vector<pli>,greater<pli>> q;
  for (int v : s) {
    dist[v] = 0;
    q.push(make_pair(0,v));
  }
  while (!q.empty()) {
    auto [d, v] = q.top(); q.pop();
    if (dist[v] < d) continue;
    vector<pli> edges = adj(v);
    for (auto [cost, u] : edges) {
      if (dist[v] + cost < dist[u]) {
        dist[u] = dist[v] + cost;
        q.push(make_pair(dist[u], u));
      }
    }
  }
  return dist;
}

int main() {
  scanf("%d%d%d",&n,&k,&m);
  REP(i,k) {
    scanf("%d",&city[i]);
    --city[i];
  }
  REP(i,m) {
    int a,b,c; scanf("%d%d%d",&a,&b,&c);
    --a; --b;
    adj[a].emplace_back(ll(c), b);
    adj[b].emplace_back(ll(c), a);
  }

  REP(i,k) {
    dist[i] = dijkstra(n, { city[i] }, [](int v) { return adj[v]; });
  }

  auto graph_adj = [](int v) {
    int w = v%n, mask = v/n;
    vector<pli> ans;
    for (auto [cost, u] : adj[w]) {
      ans.emplace_back(cost, u + mask*n);
    }
    REP(i,k) if (!(mask & 1<<i)) {
      ans.emplace_back(dist[i][w], w + (mask | (1<<i))*n);
    }
    return ans;
  };

  vector<int> s;
  REP(i,n) s.push_back(i);
  vector<ll> graph_dist = dijkstra(n*(1<<k), s, graph_adj);

  ll ans = 1e18;
  REP(i,n) {
    ans = min(ans, graph_dist[i + ((1<<k)-1)*n]);
  }

  printf("%lld\n", ans);
}