0w1

HE Zulu and Alarm Clock ( MCMF )

https://www.hackerearth.com/problem/algorithm/zulu-and-alarm-clock-1/

題意:
T 筆測資。
N 個鬧鐘,K 個時間。
你要把 K 個鬧鐘調成這 K 個時間。
你可以上下調整時、秒、分,會進位退位。
問最小調整次數。

制約:
1≤T≤2
1≤N≤50
1≤K≤17

解法:
可以用遮罩動態規劃亂搞。
但是直覺很 MCMF。
先跑一遍最短路徑,給鬧鐘和目標時間建弧,費用就是最短路徑。
MCMF 亂流。

#include <bits/stdc++.h>
using namespace std;

template< class TF, class TC >
struct CostFlow {
  static const int MAXV = 205;
  static const TC INF = 0x3f3f3f3f;
  struct Edge {
    int v, r;
    TF f;
    TC c;
    Edge( int _v, int _r, TF _f, TC _c ): v( _v ), r( _r ), f( _f ), c( _c ) {}
  };
  int n, s, t, pre[ MAXV ], pre_E[ MAXV ], inq[ MAXV ];
  TF fl;
  TC dis[ MAXV ], cost;
  vector< Edge > E[ MAXV ];
  CostFlow( int _n, int _s, int _t ): n( _n ), s( _s ), t( _t ), fl( 0 ), cost( 0 ) {}
  void add_edge( int u, int v, TF f, TC c ) {
    E[ u ].emplace_back( v, E[ v ].size(), f, c );
    E[ v ].emplace_back( u, E[ u ].size() - 1, 0, -c );
  }
  pair< TF, TC > flow() {
    while( true ) {
      for( int i = 0; i < n; ++i ) {
        dis[ i ] = INF;
        inq[ i ] = 0;
      }
      dis[ s ] = 0;
      queue< int > que;
      que.emplace( s );
      while( not que.empty() ) {
        int u = que.front();
        que.pop();
        inq[ u ] = 0;
        for( int i = 0; i < E[ u ].size(); ++i ) {
          int v = E[ u ][ i ].v;
          TC w = E[ u ][ i ].c;
          if( E[ u ][ i ].f > 0 and dis[ v ] > dis[ u ] + w ) {
            pre[ v ] = u;
            pre_E[ v ] = i;
            dis[ v ] = dis[ u ] + w;
            if( not inq[ v ] ) {
              inq[ v ] = 1;
              que.emplace( v );
            }
          }
        }
      }
      if( dis[ t ] == INF ) break;
      TF tf = INF;
      for( int v = t, u, l; v != s; v = u ) {
        u = pre[ v ];
        l = pre_E[ v ];
        tf = min( tf, E[ u ][ l ].f );
      }
      for( int v = t, u, l; v != s; v = u ) {
        u = pre[ v ];
        l = pre_E[ v ];
        E[ u ][ l ].f -= tf;
        E[ v ][ E[ u ][ l ].r ].f += tf;
      }
      cost += tf * dis[ t ];
      fl += tf;
    }
    return { fl, cost };
  }
};

int N, K;
tuple< int, int, int > clk[ 50 ];
tuple< int, int, int > ala[ 17 ];

tuple< int, int, int > convert( string s ) {
  return make_tuple( stoi( s.substr( 0, 2 ) ), stoi( s.substr( 3, 2 ) ), stoi( s.substr( 6, 2 ) ) );
}

tuple< int, int, int > tick( tuple< int, int, int > u, int x, int d ) {
  int c[ 3 ];
  tie( c[ 0 ], c[ 1 ], c[ 2 ] ) = u;
  c[ x ] += d;
  for( int i = 3 - 1; i >= 0; --i ) {
    if( i ) {
      if( c[ i ] < 0 ) {
        c[ i ] += 60;
        --c[ i - 1 ];
      } else if( c[ i ] >= 60 ) {
        c[ i ] -= 60;
        ++c[ i - 1 ];
      }
    } else {
      if( c[ i ] < 0 ) {
        c[ i ] += 24;
      } else if( c[ i ] >= 24 ) {
        c[ i ] -= 24;
      }
    }
  }
  return make_tuple( c[ 0 ], c[ 1 ], c[ 2 ] );
}

void sssp( CostFlow< int, int > &mcmf, int si ) {
  static int dis[ 24 ][ 60 ][ 60 ];
  memset( dis, 0x3f, sizeof( dis ) );
  queue< pair< int, tuple< int, int, int > > > que;
  que.emplace( 0, clk[ si ] );
  while( not que.empty() ) {
    int d;
    tuple< int, int, int > u;
    tie( d, u ) = que.front();
    que.pop();
    for( int i = 0; i < 3; ++i ) {
      for( int j = -1; j <= 1; ++j ) if( j != 0 ) {
        tuple< int, int, int > v = tick( u, i, j );
        int a, b, c;
        tie( a, b, c ) = v;
        if( dis[ a ][ b ][ c ] <= d + 1 ) continue;
        que.emplace( dis[ a ][ b ][ c ] = d + 1, v );
      }
    }
  }
  for( int i = 0; i < K; ++i ) {
    int a, b, c;
    tie( a, b, c ) = ala[ i ];
    mcmf.add_edge( si, N + i, 1, dis[ a ][ b ][ c ] );
  }
}

signed main() {
  ios::sync_with_stdio( 0 );
  int T;
  cin >> T;
  for( int ti = 0; ti < T; ++ti ) {
    cin >> N >> K;
    for( int i = 0; i < N; ++i ) {
      string s;
      cin >> s;
      clk[ i ] = convert( s );
    }
    for( int i = 0; i < K; ++i ) {
      string s;
      cin >> s;
      ala[ i ] = convert( s );
    }
    int SOURCE = N + K;
    int SINK = N + K + 1;
    CostFlow< int, int > mcmf( N + K + 2, SOURCE, SINK );
    for( int i = 0; i < N; ++i ) {
      mcmf.add_edge( SOURCE, i, 1, 0 );
    }
    for( int i = 0; i < K; ++i ) {
      mcmf.add_edge( N + i, SINK, 1, 0 );
    }
    for( int i = 0; i < N; ++i ) {
      sssp( mcmf, i );
    }
    cout << mcmf.flow().second << endl;
  }
  return 0;
}