SRM471 Div1 Medium(500) ThirteenHard
ThirteenHard
今3番目の駅に居るとして、
(T1+T2+T3)%13=a,
(T2+T3)%13=b,
(T3)%13=c,
とすると、
(T1+T2+T3+T4)%13=(a+T4)%13,
(T2+T3+T4)%13=(b+T4)%13,
(T3+T4)%13=(c+T4)%13,
である。
駅の番号と、各駅からその駅までの距離を13で割った余りのビット表現を合わせて1つのノードとした最短経路問題を解く。
最短路が通る辺の数に比べてノード数が多いので、ソートも無しの単純なダイクストラでは間に合わなかったけど、ベルマン・フォードっぽい方法はOKだった。
#include <string> #include <vector> #include <climits> #include <algorithm> using namespace std; class ThirteenHard { int time( char c ); public: int calcTime( vector <string> city ); }; int ThirteenHard::time( char c ) { if ( 'A' <= c && c <= 'Z' ) return c - 'A' + 1; if ( 'a' <= c && c <= 'z' ) return c - 'a' + 27; return -1; } int ThirteenHard::calcTime( vector <string> city ) { int N = (int)city.size(); vector<vector<int> > T( N, vector<int>( 1<<13, INT_MAX ) ); vector<vector<bool> > F( N, vector<bool>( 1<<13, false ) ); T[0][0] = 0; F[0][0] = true; bool update; do { update = false; for ( int fc=0; fc<N; fc++ ) for ( int fr=0; fr<1<<13; fr++ ) if ( F[fc][fr] ) { for ( int tc=0; tc<N; tc++ ) { int t = time( city[fc][tc] ); if ( t >= 0 ) { int tr = 1<<(t%13); for ( int i=0; i<13; i++ ) tr |= (fr>>i&1)<<((i+t)%13); if ( (tr&1) == 0 && T[tc][tr] > T[fc][fr] + t ) { update = true; T[tc][tr] = T[fc][fr] + t; F[tc][tr] = true; } } } F[fc][fr] = false; } } while ( update ); int ans = *min_element( T[N-1].begin(), T[N-1].end() ); return ans<INT_MAX ? ans : -1; }