Cod sursa(job #115175)

Utilizator flo_demonBunau Florin flo_demon Data 16 decembrie 2007 11:21:48
Problema Gather Scor 0
Compilator cpp Status done
Runda preONI 2008, Runda 2, Clasele 11-12 Marime 4.58 kb
#include <stdio.h>
#include <vector>
#include <queue>
#include <map>

using namespace std;

#define MAX_CELLS 752
#define INF 2000000000

struct muchie {
    int nod;     // nodul spre care merge muchia
    int lung;    // lungimea muchiei 
    int cap;     // capacitatea maxima
};

struct stare {
    int nod;     // nodul in care se afla gigel
    int det;     // ce detinuti avem cu noi, codificati pe biti (al -ilea bit setat, avem al i-lea detinut)
    int lung;    // ce lungime am parcurs
};

// ce codificare ne trebuie pt. evadare (toti detinutii)
int full[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767 };

int k, n, m;                     // nr de detinuti, nr celule, nr. muchii
map<int, int> detinuti;          // ce detinut(nr) e in celula i
vector<muchie> a[MAX_CELLS];     // ce muchii pornesc din nodul i 
queue<stare> Q;                  // coada starilor

int dp[MAX_CELLS][(1<<16)+8];    // am ajuns pana in i cu detinutii codificati ca j, parcurgang lungimea minima
int rez = INF;                   // raspunsul

int main()
{
    int nod1, nod2, auxlung, auxcap;
    muchie currm;
    stare curr;
    int curr_nod, curr_det, curr_lung, auxdet, cntdet;
    
    FILE *fin = fopen("gather.in", "r");
    fscanf(fin, "%d%d%d", &k, &n, &m);
    for (int i = 0; i < k; ++i)
    {
        fscanf(fin, "%d", &nod1);
        detinuti[nod1] = i;
    }
    for (int i = 0; i < m; ++i)
    {
        fscanf(fin, "%d%d%d%d", &nod1, &nod2, &auxlung, &auxcap);
        currm.nod = nod2;
        currm.lung = auxlung;
        currm.cap = auxcap;
        a[nod1].push_back(currm);
        currm.nod = nod1;
        a[nod2].push_back(currm);
    }
    fclose(fin);
    
    // init
    for (int i = 0; i <= n; ++i)
        for (int j = 0; j <= ((1 << (k+1)) + 3); ++j)
            dp[i][j] = INF;
    
    // pornim din celula 0, spre celula 1 (lungime 0)
    curr.nod = 0;
    curr.det = 0;
    curr.lung = 0;
    Q.push(curr);
    // legam celula 0 de 1
    currm.nod = 1;
    currm.lung = 0;
    currm.cap = 2000000000;
    a[0].push_back(currm);
    
    while (!Q.empty())
    {
        curr = Q.front();
        Q.pop();
        curr_nod = curr.nod;
        curr_det = curr.det;
        curr_lung = curr.lung;
        auxdet = curr.det;
        //
        if (auxdet == full[k]) // daca am strans toti detinutii
            if (rez > curr_lung)
                rez = curr_lung;
        // daca avem sau am avut in coada o stare mai buna decat cea curenta, ignora
        if (dp[curr_nod][curr_det] < curr_lung) 
            continue;
            
        // nu ii zicem detinutului planul sau celula nu are detinut
        cntdet = 0; // nr de detinuti care ii avem cu noi
        for (int i = 0; i <= k; ++i)
            if (((auxdet >> i) & 1))
                cntdet++;
        for (int j = 0; j < a[curr_nod].size(); ++j)
            if (a[curr_nod][j].cap >= cntdet)
                if (dp[a[curr_nod][j].nod][auxdet] > curr_lung + (cntdet+1) * a[curr_nod][j].lung)
                {
                    dp[a[curr_nod][j].nod][auxdet] = curr_lung + (cntdet+1) * a[curr_nod][j].lung;
                    curr.nod = a[curr_nod][j].nod;
                    curr.det = auxdet;
                    curr.lung = curr_lung + (cntdet+1) * a[curr_nod][j].lung;
                    Q.push(curr);
                }
        // daca avem detinut
        if (detinuti.find(curr_nod) != detinuti.end())
        {
            // ii spunem
            auxdet |= (1 << detinuti[curr_nod]);
            if (auxdet == full[k]) // daca am strans toti detinutii
                if (rez > curr_lung)
                    rez = curr_lung;
            
            cntdet = 0; // nr de detinuti care ii avem cu noi
            for (int i = 0; i <= k; ++i)
                if (((auxdet >> i) & 1))
                   cntdet++;
            for (int j = 0; j < a[curr_nod].size(); ++j)
                if (a[curr_nod][j].cap >= cntdet)
                   if (dp[a[curr_nod][j].nod][auxdet] > curr_lung + (cntdet+1) * a[curr_nod][j].lung)
                   {
                      dp[a[curr_nod][j].nod][auxdet] = curr_lung + (cntdet+1) * a[curr_nod][j].lung;
                      curr.nod = a[curr_nod][j].nod;
                      curr.det = auxdet;
                      curr.lung = curr_lung + (cntdet+1) * a[curr_nod][j].lung;
                      Q.push(curr);
                   }
        }
        
    }
    
    FILE *fout = fopen("gather.out", "w");
    fprintf(fout, "%d\n", rez);
    fclose(fout);
    
    return 0;
}