Pagini recente » Cod sursa (job #930192) | Cod sursa (job #877183)
Cod sursa(job #877183)
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <set>
#include <queue>
#include <deque>
using namespace std;
ifstream f("gather.in");
ofstream g("gather.out");
#define nmax 752
#define Kmax 16
#define Mmax 1255
#define ll long long
#define inf (1<<29)
int K, n, m, Cost[Kmax+1][Kmax+1][Kmax+1] , dist[nmax], dp[(1<<Kmax)+1][Kmax+1];
set< pair<int,int> > S;
vector< pair<int, pair<int,int> > > gf[nmax];
int Det[Kmax+1];
void citeste(){
f >> K >> n >> m;
Det[1] = 1;// detinutul Gigel
//++K;
for(int i=2; i<=K; ++i) f>>Det[i];
int x, y, c, d;
for(int i=1; i<=m; ++i){
f >> x >> y >> c >> d;
gf[x].push_back( make_pair( y, make_pair(c, d) ) );
gf[y].push_back( make_pair( x, make_pair(c, d) ) );
}
}
void Dijkstra(int s, int d, int k){
for(int i=1; i<=n; ++i) dist[i] = inf;
for(; S.size(); S.erase(S.begin()));
dist[s] = 0; S.insert( make_pair(0, s) );
for(; S.size(); ){
int nod = (*S.begin()).second; int Min = (*S.begin()).first;
S.erase(S.begin());
if (nod == d) return;// am ajuns la destinatie
for(int i=0; i<gf[nod].size(); ++i){
int vc = gf[nod][i].first;
int cost = gf[nod][i].second.first;
int Maxd = gf[nod][i].second.second;// numarul maxim de detinuti
if (dist[vc] > Min + cost && Maxd >= k){
dist[vc] = Min + cost;
S.insert( make_pair( dist[vc], vc ) );
}
}
}
}
void bagaDistante(){
for(int i=0; i<=K; ++i){
for(int j=0; j<=K; ++j){
//for(int k=0; k<=K; ++k) Cost[i][j][k] = inf;
}
}
for(int i=1; i<=K; ++i){
for(int j=i+1; j<=K; ++j){
// fac distanta minima de la al i-lea detinut la al j-lea detinut / evident si de la j la i tot atata va fi
// doar ca vreau ca pe drumul asta pe orice muchie sa ma pot duce cu K detinuti
for(int k=0; k<=K; ++k){// gigel nu e contorizat ca si detinut
Dijkstra(Det[i], Det[j], k);
Cost[i][j][k] = dist[ Det[j] ];
Cost[j][i][k] = dist[ Det[j] ];
//cout << Det[i] << " " << Det[j] << " " << k << " " << dist[j] << "\n";
}
}
}
}
void rezolva(){
// in primul rand am solutia ar fi o dinamica gen dp[conf][j] = timpul minim parcurs de detinutii din conf stiind ca ultimul
// care se alatura e al j-lea; numai ca pentru asta j-ul o sa continui un conf2 , k si imi trebuie distanta minima de la k la j
// iar acum vreau distana minima de k , j a. vand invedere ca pe orice muchie de pe drumul asta minim pot sa ma duc cu detinutii
// deci mai trebuie o dinamica dp[i][j][k] = distanta minima de la i la j stiind ca pe orice muchie de la i la j ma pot duce cu cel putin k detinuti
// fac a 2 -a dinamica
bagaDistante();
// si acum bag prima dinamica
for(int i=0; i<(1<<K); ++i) for(int j=0; j<=K; ++j) dp[i][j] = inf;
dp[1][1] = 0;// detinutul gigel de la el pornesc
int lim = (1<<K);
for(int conf = 3; conf<lim; ++conf){
int cnt = 0;
for(int j=0; j<K; ++j)
if ( conf & (1<<j) ) ++cnt;// cati detinuti am
--cnt;// il scad pe gigel (el nu se pune)
for(int j=0; j<K; ++j){// deci sunt vreau sa ajung in j;
if ( conf & (1<<j) ){
int precConf = conf - (1<<j); // scad acest detinut
for(int k=0; k<K; ++k){
if ( precConf & (1<<k) ){// si stiu ca vin din precConf, k
if (Cost[k+1][j+1][cnt-1] == inf || dp[precConf][k+1] == inf) continue;
dp[conf][j+1] = min(dp[conf][j+1], dp[precConf][ k+1 ] + (Cost[ k+1 ][ j+1 ][cnt-1] * (cnt) ) );
//cout << precConf << " " << k+1 << " " << j+1<< " " << cnt << " " << Cost[k+1][j+1][cnt-1] << "\n";// + (Cost[ k ][ j ][cnt-1] * (cnt) ) << '\n';
}
}
}
//cout <<conf << " " << j+1 << " " << dp[conf][j+1] << " " << cnt << "\n";
}
}
int Min = inf;
for(int i=2; i<=K; ++i) Min = min( dp[lim-1][i], Min );
cout << Min << "\n";
g << Min << "\n";
}
int main(){
citeste();
rezolva();
f.close();
g.close();
return 0;
}