Pagini recente » Cod sursa (job #2441731) | Cod sursa (job #489263) | Cod sursa (job #1805725) | Cod sursa (job #809380) | Cod sursa (job #1882039)
//Complexitate O(((M log2 N) * K) + (2^K) * (K^2))
#include <fstream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
ifstream f("ubuntzei.in");
ofstream g("ubuntzei.out");
const int NMAX = 2002;
const int KMAX = 16;
const int inf = 0x3f3f3f3f;
int N, M, K;
vector <pair<int,int>> G[NMAX];
vector <int> Localitati;
vector <int> Distanta_Initiala; //distantele minime din nodul sursa
vector <int> Distanta_Localitati[KMAX]; //distantele minime din fiecare localitate din cele K
int dp[KMAX][1 << KMAX]; //dp[i][s] - costul minim de a ajunge in nodul i , unde s este o submultime a celor K localitati prin care trebuie sa trecem
//fiecare K[i] - localitate va fi reprezentata de al i-lea bit din valoarea lui s
//recurenta este : dp[i][j] = dp[j][s-{i}] + dist_min(j, i) , unde j apartine lui s si i != j (nu exista cicluri)
void Dijkstra(int, vector <int> & );
int main()
{
//citim
f >> N >> M >> K;
Localitati = vector <int> (K + 1);
for (int i = 0; i < K; ++i)
f >> Localitati[i];
for (int i = 1; i <= M; ++i)
{
int x, y, c;
f >> x >> y >> c;
G[x].push_back({y, c});
G[y].push_back({x, c});
}
//aflam vectorii de distante - O((M log2 N) * K)
Dijkstra(1, Distanta_Initiala);
if (K == 0)
{
g << Distanta_Initiala[N];
return 0;
}
for (int i = 0; i < K; ++i)
Dijkstra(Localitati[i], Distanta_Localitati[i]);
//aplicam dinamica - O((2^K) * (K^2))
//initializare a starii formate doar din nodul i prin drumul de la 1
for (int i = 0; i < K; ++i)
dp[i][(1 << i)] = Distanta_Initiala[Localitati[i]];
for (int s = 1; s < (1 << K); ++s) //pt orice stare
{
for (int i = 0; i < K; ++i) //pt orice localitate
if ((1 << i) < s) //daca starea actuala e diferita de cazul cand multimea e formata doar din localitatea initiala
{
dp[i][s] = inf;
if ( ((s >> i) & 1) == 1) //daca al i-lea bit a lui s este 1 (deci starea respectiva trece prin i)
for (int j = 0; j < K; ++j) //cautam pt orice alta localitate
if (j != i && ((s >> j) & 1 ) == 1) //o alta stare intermediara precedenta unde si al j-lea bit a lui s este 1
{
//daca da inseamna ca am ajuns intr-o recurenta buna
int cost_curent = dp[j][s - (1 << i)] + Distanta_Localitati[j][Localitati[i]]; //calculam un cost posibil dupa recurenta scrisa sus
dp[i][s] = min(dp[i][s], cost_curent); //alegem minimul
}
}
}
//calculam bestul care minimul dintre toate starile dp[i][(1 << K) - 1] + dist(i,N) , unde (1 << K) - 1 reprezinta 2^K - 1, deci o reprezentare plina de 1 : adica toate cele K localitati
int best = inf; //dist(i,N) - distanta ramasa din ultima localitate obligatorie pana la destinatia finala
for (int i = 0; i < K; ++i)
best = min(best, dp[i][(1 << K) - 1] + Distanta_Localitati[i][N]);
g << best;
f.close();
g.close();
}
void Dijkstra(int start, vector <int> & D)
{
priority_queue <pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> Q;
D = vector <int> (NMAX, inf);
D[start] = 0;
Q.push({0, start});
while (!Q.empty())
{
int x = Q.top().second, dx = Q.top().first;
Q.pop();
if (dx > D[x])
continue;
for (const pair<int,int> & p : G[x])
{
int y = p.first, w = p.second;
if (D[y] > D[x] + w)
{
D[y] = D[x] + w;
Q.push({D[y], y});
}
}
}
}