Cod sursa(job #877174)

Utilizator vendettaSalajan Razvan vendetta Data 12 februarie 2013 17:30:44
Problema Gather Scor 70
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.31 kb
#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;
}