Pagini recente » Cod sursa (job #783350) | Cod sursa (job #2114987) | Cod sursa (job #2732151) | Cod sursa (job #1286954) | Cod sursa (job #1477939)
#include <fstream>
#include <vector>
#include <queue>
#include <bitset>
const int MAX_K = 15;
const int MAX_N = 2000;
const int MAX_M = 100000;
const int BUFFSIZE = 4096;
const int INF = 2000000000;
const int NIL = -1;
const char IN [ ] = "ubuntzei.in" ;
const char OUT[ ] = "ubuntzei.out";
using namespace std;
#define pb emplace_back
#define mp make_pair
typedef pair < int, int > PII ;
ofstream cout( OUT );
//pentru parsare
char buffer [ BUFFSIZE ];
int pos = BUFFSIZE;
// date citite
int n; // numarul de noduri
int node [ MAX_K + 2 ]; // nodurile prin care trebuie trecut
struct {
int v, cost, next;
} l [ 2 * MAX_M ];
int adj [ MAX_N ];
// pentru dinamica
int dist [ MAX_K + 2 ][ MAX_K + 2 ]; // dist [ i ][ j ] = distana minima pornind din nodul node [ i ] pana in node [ j ]
int din [ ( 1 << ( MAX_K + 2 ) ) ][ MAX_K + 2 ]; // din [ mask ][ j ] = distana minima folosind un drum de configuratie mask pana in node [ j ]
// pentru dijkstra
int d [ MAX_N ]; // distante minime
struct cmp // prioriteaza distana minima
{
bool operator () ( const int &a, const int &b )
{
return d [ a ] > d [ b ];
}
};
priority_queue < int, vector < int > , cmp > heap;
bitset < MAX_N > seen ;
void dijkstra ( int nod )
{
for ( int i = 0; i < n; i ++ )
d [ i ] = INF;
seen.reset ( );
heap.push ( nod );
d [ nod ] = 0;
while ( !heap.empty ( ) )
{
nod = heap.top ( );
heap.pop ( );
if ( seen [ nod ] ) continue ;
seen [ nod ] = 1;
for ( int i = adj [ nod ]; i != NIL; i = l [ i ].next )
{
int son = l [ i ].v;
int newCost = d [ nod ] + l [ i ].cost;
if ( d [ son ] > newCost )
{
d [ son ] = newCost;
heap.push ( son );
}
}
}
}
inline char getChr ( )
{
if ( pos == BUFFSIZE )
{
fread ( buffer, 1, BUFFSIZE, stdin );
pos = 0;
}
return buffer [ pos ++ ];
}
inline int readInt ( )
{
int q = 0;
char c;
do
{
c = getChr ( );
} while ( !isdigit ( c ) );
do
{
q = ( q << 1 ) + ( q << 3 ) + ( c - '0' );
c = getChr ( );
} while ( isdigit ( c ) );
return q;
}
inline 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;
}
int main ( void )
{
freopen ( IN, "r", stdin );
int m, k;
int u, v, c;
n = readInt ( );
m = readInt ( );
k = readInt ( );
node [ 0 ] = 0;
for ( int i = 1; i <= k; i ++ )
node [ i ] = readInt ( ) - 1;
node [ k + 1 ] = n - 1;
for ( int i = 0; i < n; i ++ )
adj [ i ] = NIL;
for ( int i = 0; i < m; i ++ )
{
u = readInt ( ) - 1;
v = readInt ( ) - 1;
c = readInt ( );
addEdge ( u, v, c, 2 * i );
addEdge ( v, u, c, 2 * i + 1 );
}
fclose ( stdin );
for ( int i = 0; i <= k; i ++ )
{
dijkstra ( node [ i ] ); // facem un dijkstra pentru fiecare nod prin care trebuie sa trecem
for ( int j = 0; j <= k + 1; j ++ )
{
dist [ i ][ j ] = d [ node [ j ] ]; // si retinem distanta intre 2 noduri prin care trebuie sa trecem
}
}
for ( int i = 1; i < ( 1 << k ); i ++ )
{
for ( int j = 0; j < k; j ++ )
din [ i ][ j ] = INF;
}
for ( int i = 1; i < ( 1 << k ); i ++ )
{
for ( int j = 0; j < k; j ++ )
{
if ( ( i >> j ) & 1 ) // daca j face parte din drumul curent
{
if ( !( i & ( i - 1 ) ) ) // daca drumul curent il contine doar pe j, atunci luam distanta de la nodul 0 la node [ j ]
{
din [ i ][ j ] = dist [ 0 ][ j + 1 ];
}
else
{
for ( int p = 0; p < k; p ++ )
{
if ( ( i >> p ) & 1 ) // daca p face parte din drumul curent
// consideram costul drumului curent fara j la care adaugam costul de la node [ p ] la node [ j ]
din [ i ][ j ] = min ( din [ i ][ j ], din [ i & ~( 1 << j ) ][ p ] + dist [ p + 1 ][ j + 1 ] );
}
}
}
}
}
if ( !k ) // nu este nevoie sa trecem prin vreun nod, deci luam distanta minima de la 0 la n - 1
u = dist [ 0 ][ 1 ];
else
{
u = INF;
for ( int i = 1; i <= k; i ++ ) // aflam min distantei de la oricare capat al traseului la nodul final
u = min ( u, din [ ( 1 << k ) - 1 ][ i - 1 ] + dist [ i ][ k + 1 ] );
}
cout << u << '\n';
cout.close ( );
return 0;
}