Pagini recente » Cod sursa (job #2327247) | Cod sursa (job #1759092) | Cod sursa (job #1433153) | Cod sursa (job #2682565) | Cod sursa (job #1522538)
#include <cstdio>
#include <queue>
#include <algorithm>
using std::min;
const int MAX_K = 15 + 1; // + 1 pentru Gigel
const int MAX_N = 750;
const int MAX_M = 1250;
const int NIL = -1;
const long long INF = 0x3F3F3F3F3FLL;
struct Edge {
int v, next;
long long cost, cap;
};
/* datele citite */
Edge l[2 * MAX_M]; // buffer pentru liste
int adj[MAX_N]; // capete de liste
int p[MAX_K]; // cele k + 1 valori, p[0] = 0 (Gigel)
int n;
/* pentru SPFA */
long long d[MAX_N]; // distante minime din SPFA
bool inQueue[MAX_N]; // marcare elemente in coada pentru SPFA
std::queue <int> q; // coada SPFA
/* pentru Hamilton */
long long DP[MAX_K][MAX_K][MAX_N]; // DP[i][j][u] -> costul mimim folosind doar drumuri cu capactitate >= j de la i la u
unsigned char popCount[1 << MAX_K]; // numarul de biti pentru fiecare numar de la 0 la 2^k
long long H[1 << MAX_K][MAX_K]; // dinamica pentru ciclu hamiltonian de cost minim
int k;
void addEdge(int u, int v, long long cost, long long capacity, int pos) {
l[pos].v = v;
l[pos].cost = cost;
l[pos].cap = capacity;
l[pos].next = adj[u];
adj[u] = pos;
}
/* gaseste toate distantele minime folosind doar muchii cu capacitati >= minCap */
void spfa(int u, long long minCap) {
for (int i = 0; i < n; i++) {
d[i] = INF;
}
q.push(u);
d[u] = 0;
while (!q.empty()) {
u = q.front();
q.pop();
inQueue[u] = 0;
for (int i = adj[u]; i != NIL; i = l[i].next) {
if (l[i].cap >= minCap) {
int v = l[i].v;
long long cost = d[u] + l[i].cost;
if (d[v] > cost) {
d[v] = cost;
if (!inQueue[v]) {
inQueue[v] = 1;
q.push(v);
}
}
}
}
}
}
/* dinamica cu memoizare pentru ciclu Hamiltonian de cost minim */
long long go(int mask, long long node) {
if (H[mask][node]) {
return H[mask][node];
}
long long q = INF;
if (mask == (1 << k) - 1) {
q = 0;
} else {
for (int i = 0; i < k; i++) {
if (!((mask >> i) & 1)) {
// inmulteste cu popCount[mask] pentru ca toti detinutii din mask vor merge pe acel drum
q = min(q, go(mask ^ (1 << i), i) + popCount[mask] * DP[node][ popCount[mask] ][ p[i] ]);
}
}
}
return H[mask][node] = q;
}
int main(void) {
freopen("gather.in", "r", stdin);
freopen("gather.out", "w", stdout);
int m;
int u, v;
long long cost, capacity;
scanf("%d%d%d", &k, &n, &m);
p[0] = 0;
for (int i = 1; i <= k; i++) {
scanf("%d", &p[i]);
p[i]--;
}
k++;
for (int i = 0; i < n; i++) {
adj[i] = NIL;
}
for (int i = 0; i < m; i++) {
scanf("%d%d%lld%lld", &u, &v, &cost, &capacity);
// adauga 1 la capacity pentru ca Gigel trece neobservat
addEdge(u - 1, v - 1, cost, capacity + 1, 2 * i);
addEdge(v - 1, u - 1, cost, capacity + 1, 2 * i + 1);
}
fclose(stdin);
// face SPFA pentru fiecare p[i] si toate capacitatile [1, k)
for (int i = 0; i < k; i++) {
for (int j = 1; j < k; j++) {
spfa(p[i], j);
for (u = 0; u < n; u++) {
DP[i][j][u] = d[u];
}
}
}
for (int i = 1; i < (1 << k); i++) {
popCount[i] = (i & 1) + popCount[i >> 1];
}
printf("%lld\n", go(1, 0));
fclose(stdout);
return 0;
}