SRM490 Div1 Medium(550) QuickT9
Dが空文字列になったときで区切って考える。それぞれの文字列は数字を1回以上、その後Rightを1回かCを1回以上入力して得られる文字列。各文字列について最小タイプ数を求めて、動的計画法。
#include <vector> #include <string> #include <map> #include <set> #include <sstream> using namespace std; vector<string> dic; // 辞書 vector<string> digit; // 辞書の入力に必要なキーストローク map<string,int> type; // 添字の入力に必要なタイプ数 void BT( string D ) { int l = (int)D.length(); // validな文字列 set<string> U; for ( int i=0; i<(int)dic.size(); i++ ) if ( digit[i].length() >= D.length() && digit[i].substr(0,l) == D ) U.insert( dic[i].substr(0,l) ); // validな文字列それぞれに対して // Right もしくは C を連打したときの文字列とタイプ数を求める int c = 0; for ( set<string>::iterator u=U.begin(); u!=U.end(); u++, c++ ) for ( int i=1; i<=l; i++ ) { string s = u->substr(0,i); int t = i==l ? l+c+1 : l+c+(l-i); if ( type.count(s) == 0 || type[s] > t ) type[s] = t; } // validな文字列がまだあれば探索 if ( U.size() > 0 ) for ( int i=2; i<=9; i++ ) BT( D + char('0'+i) ); } class QuickT9{public: int minimumPressings( vector <string> t9, string word ) { // 辞書 dic.clear(); for ( int i=0; i<(int)t9.size(); i++ ) { stringstream ss( t9[i] ); string d; while ( ss >> d ) dic.push_back( d ); } // キーストローク int button[26] = { 2,2,2, 3,3,3, 4,4,4, 5,5,5, 6,6,6, 7,7,7,7, 8,8,8, 9,9,9,9 }; digit.clear(); for ( int i=0; i<(int)dic.size(); i++ ) { digit.push_back( "" ); for ( int j=0; j<(int)dic[i].length(); j++ ) digit.back() += char( '0' + button[dic[i][j]-'a'] ); } // 辞書の部分文字列の打つのに必要な最小タイプ数を求める type.clear(); for ( int i=2; i<=9; i++ ) BT( string(1,'0'+i) ); // DP int n = word.size(); int inf = 99999999; vector<int> T( n+1, inf ); // wordの先頭i文字の入力に必要なタイプ数 T[0] = 0; for ( int i=1; i<=n; i++ ) for ( int j=0; j<i; j++ ) { string s = word.substr(j,i-j); if ( type.count(s) > 0 ) T[i] = min( T[i], T[j]+type[s] ); } return T[n]<inf ? T[n] : -1; }};