Cod sursa(job #2766878)

Utilizator Alex_tz307Lorintz Alexandru Alex_tz307 Data 3 august 2021 18:55:00
Problema Gather Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.28 kb
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f

using namespace std;

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

const int MAXK = 16;
const int MAXN = 750;
int d[MAXK];
vector<tuple<int,int,int>> G[MAXN];
int dp[MAXK][1 + MAXK][1 + MAXN], a[MAXK][1 << MAXK];
/// dp[i][j][nod] - costul minim pentru a ajunge de la nodul in care se afla detinutul cu numarul i la nod
///                 folosind doar muchii cu capacitatea >= j
/// a[i][mask] - costul minim pentru a aduce in celula detinutului i toti detinutii al caror bit este setat in mask
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq;

void Dijkstra(int s, int low, int D[]) {
  D[s] = 0;
  pq.emplace(D[s], s);
  while (!pq.empty()) {
    int dist, u;
    tie(dist, u) = pq.top();
    pq.pop();
    if (dist != D[u])
      continue;
    for (auto it : G[u]) {
      int v, w, c;
      tie(v, w, c) = it;
      if (c >= low && D[v] > D[u] + w) {
        D[v] = D[u] + w;
        pq.emplace(D[v], v);
      }
    }
  }
}

void min_self(int &x, int y) {
  if (x > y)
    x = y;
}

int main() {
  int k, n, m;
  fin >> k >> n >> m;
  ++k;
  for (int i = 1; i < k; ++i) {
    fin >> d[i];
    --d[i];
  }
  for (int i = 0; i < m; ++i) {
    int u, v, w, c;
    fin >> u >> v >> w >> c;
    --u, --v;
    G[u].emplace_back(v, w, c);
    G[v].emplace_back(u, w, c);
  }
  memset(dp, INF, sizeof dp);
  for (int i = 0; i < k; ++i)
    for (int j = 0; j <= k; ++j)
      Dijkstra(d[i], j, dp[i][j]);
  memset(a, INF, sizeof a);
  a[0][1] = 0;
  for (int mask = 2; mask < (1 << k); ++mask) {
    int cnt_det = __builtin_popcount(mask) - 1; /// Gigel nu trebuie numarat(capacitatile muchiilor limiteaza numarul de prizonieri doar)
    for (int i = 0; i < k; ++i)
      if (mask & (1 << i)) {
        int prev_mask = mask ^ (1 << i);
        for (int j = 0; j < k; ++j) {
          if (a[j][prev_mask] == INF || dp[j][cnt_det - 1][d[i]] == INF)
            continue;
          min_self(a[i][mask], a[j][prev_mask] + cnt_det * dp[j][cnt_det - 1][d[i]]); /// detinutul i nu trebuie numarat
        }
      }
  }
  int ans = INF;
  for (int i = 0; i < k; ++i)
    min_self(ans, a[i][(1 << k) - 1]);
  fout << ans << '\n';
  fin.close();
  fout.close();
  return 0;
}