Cod sursa(job #877448)

Utilizator vendettaSalajan Razvan vendetta Data 12 februarie 2013 21:10:28
Problema Gather Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.67 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)
#define Cifmax (1<<14)

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];
char s[Cifmax]; int poz;

void buf(int &nr){
    nr = 0;
    while( s[poz] < '0' || s[poz] > '9' ){
        ++poz; if (poz == Cifmax){
            fread(s, 1, Cifmax, stdin);
            poz = 0;
        }
    }
    while( s[poz] >= '0' && s[poz] <= '9'){
        nr = nr * 10 + (s[poz] - '0');
        ++poz; if (poz == Cifmax){
            fread(s, 1, Cifmax, stdin);
            poz = 0;
        }
    }
}

void citeste(){
    //f >> K >> n >> m;
    buf(K); buf(n); buf(m);
    Det[0] = 1;// detinutul Gigel
    //++K;
    for(int i=1; i<=K; ++i) buf(Det[i]);// f>>Det[i];
    int x, y, c, d;
    for(int i=1; i<=m; ++i){
        //f >> x >> y >> c >> d;
        buf(x); buf(y); buf(c); buf(d);
        gf[x].push_back( make_pair( y, make_pair(c, d) ) );
        gf[y].push_back( make_pair( x, make_pair(c, d) ) );
    }
}

struct cmp{
    bool operator() (const int x, const int y){
        return dist[x] > dist[y];
    }
};

void Dijkstra(int s, int d, int k){
    for(int i=1; i<=n; ++i) dist[i] = inf;
    priority_queue< int, vector<int>, cmp > Q;
    dist[s] = 0; Q.push(s);
    for(; Q.size(); ){
        int nod = Q.top(); Q.pop();
        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] > dist[nod] + cost && Maxd >= k){
                dist[vc] = dist[nod] + cost;
                Q.push( vc );
            }
        }
    }

}

void bagaDistante(){
    for(int i=0; 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[0][0] = 0;// detinutul gigel de la el pornesc
   int lim = (1<<K);
   for(int conf = 1; conf<lim; ++conf){
        int cnt = 0;
        for(int j=0; j<K; ++j)
            if ( conf & (1<<j) ) ++cnt;// cati detinuti am

        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
                if (precConf == 0){
                    dp[conf][j+1] = min(dp[conf][j+1], Cost[0][j+1][cnt-1]);
                    continue;
                }
                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) ) );
                    }
                }
            }
        }
   }
   int Min = inf;
   for(int i=1; i<=K; ++i) Min = min( dp[lim-1][i], Min );
   cout << Min << "\n";
   g << Min << "\n";
}

int main(){
    freopen("gather.in", "r", stdin);

    citeste();
    rezolva();

//9    f.close();
    g.close();

    return 0;
}