Cod sursa(job #115494)

Utilizator ZeusCatalin Tiseanu Zeus Data 16 decembrie 2007 12:50:43
Problema Gather Scor 70
Compilator cpp Status done
Runda preONI 2008, Runda 2, Clasele 11-12 Marime 4.05 kb

#include <cstdio>
#include <vector>
#include <algorithm>
#include <iostream>

using namespace std;

#define data unsigned int
#define INF (1<<28)

#define MAX_N (1<<10)
#define CLR(xx) memset( xx, 0, sizeof(xx) )

int N, M, K, cnt[1<<15], prisoners[16], amin[2*MAX_N];
data dist[16][16][16], from_zero[16], hash[1<<15][15], d[MAX_N], cop[MAX_N];
char u[1<<15][16], is_prisoner[MAX_N], ru[MAX_N];

vector< data > g[MAX_N], cap[MAX_N], co[MAX_N];

inline data get_min()
{ return amin[1]; }

inline void upd( int n, data val )
{
    d[n] = val;
    
    for( int i = ( n + MAX_N ) >> 1; i; i >>= 1 )
         if( d[ amin[2*i] ] <= d[ amin[2*i+1] ] )
             amin[i] = amin[2*i];
         else
             amin[i] = amin[2*i+1];
}

void do_dijkstra( int src, int with )
{
    for( int i = 0; i <= N; ++i )
         d[i] = INF;
         
    CLR( amin ); CLR( ru );
    for( int i = 1; i <= N; i++ )
         amin[ i + MAX_N ] = i;
    
    upd( src, 0 );
    
    int el; data cur_dist;
    
    for( int step = 1; step <= N; ++step )
    {
         el = get_min();
         cur_dist = d[ el ];
         
         ru[el] = 1;
         
//         if( src == 1 )
//         { printf("d[%d] = %d\n", el, d[el] ); }
             
         cop[ el ] = cur_dist;
         upd( el, INF );
         
         for( int i = 0; i < (int)g[el].size(); i++ )
              if( !ru[ g[el][i] ] && cap[el][i] >= with && d[ g[el][i] ] > cur_dist + co[el][i] )
                  upd( g[el][i], cur_dist + co[el][i] );
    }
}

data rec( int msk, int city )
{
     if( msk == 0 )
          return from_zero[city];
     
     if( u[msk][city] )
          return hash[msk][city];
     
     u[msk][city] = 1;
     
     data & ret = hash[msk][city], cur;     
     
     ret = INF;
     
//     printf("rec(%d,%d)", msk, city );
//     printf("%d\n", msk - (1<<city) );
     
     for( int i = 0; i < K; i++ )
          if( cnt[msk] > 1 )
          {
              if( (msk >> i & 1) && i != city )
              {
                  cur = rec( msk - (1<<city), i ) + dist[i][city][ cnt[msk] - 1 ] * (cnt[msk]);
                  if( cur < ret ) ret = cur;
              }
          }
          else
          {
              cur = from_zero[ city ];
              if( cur < ret ) ret = cur; 
          }
          
//     printf("rec(%d,%d) = %d\n", msk, city, ret );
     
     return ret;
}

int main()
{
    freopen("gather.in", "r", stdin);
    freopen("gather.out", "w", stdout);
    
    scanf("%d %d %d", &K, &N, &M);
    
    for( int i = 0; i < K; i++ )
         scanf("%d", &prisoners[i] ),
         is_prisoner[ prisoners[i] ] = 1;
    
    for( int i = 1; i <= M; i++ )
    {
         unsigned A, B, C, D;
         
         scanf("%d %d %d %d\n", &A, &B, &C, &D );
         if( D >= K ) D = K;

         g[A].push_back( B ), g[B].push_back( A );
         cap[A].push_back( D ), cap[B].push_back( D );
         co[A].push_back( C ), co[B].push_back( C );    
    }
    
    for( int i = 0; i < (1<<15); ++i )
         for( int j = i; j; cnt[i] += (j&1), j /= 2 );
    
    do_dijkstra( 1, 0 );
    
    for( int i = 0; i < K; i++ )
    {
         from_zero[i] = cop[ prisoners[i] ];
//         printf("from_zero[%d] = %d\n" , i, from_zero[i] );
    }
    
    for( int i = 0; i < K; i++ )
    {
         for( int nr = K - 1; nr >= 1; nr-- )
         {
              do_dijkstra( prisoners[i], nr );     
              
              for( int j = 0; j < K; j++ )
                   if( i != j )
                   {
                       dist[ i ][ j ][ nr ] = cop[ prisoners[j] ];
                   
//                       printf("dist[%d][%d][%d] = %d\n", i, j, nr, dist[i][j][nr] );
                   }
         }    
    }
    
    data ret = INF, cur;
    
    for( int i = 0; i < K; i++ )
    {
         CLR( u );
         
         cur = rec( (1<<K) - 1, i );
         
         if( cur < ret ) ret = cur;     
    }
    
    cout << ret << endl;
    
    return 0;    
}