英文原题
中文题译
大意:给定一个单词表和一个字串,找字串的可被给定单词表表示的最长前缀的长度。
之前在POJ上做个一个恢复错排句子的题(
POJ3504),.例如,tihssnetnceemkaesprfecetsesne是一个没空格且被打错了字(除了单词的第一个和最后一个字母外其他字母的顺序有可能被敲错)的句子,可能的单词包括makes,perfect,sense,sentence,this。于是这个句子可以恢复成this sentence makes perfect sense。这题是用hash来计算的,hash函数需设计得与顺序无关。其他的部分,可以用动态规划,也可以用搜索。
用tries结构来做吧,由于本题中串均为大写字母,故最多26分叉,于是在Tries中可以不保存节点值,而是用子树的下标来隐式表示节点值,同时这样使得搜索进一步加快。用NOCOW上的程序做了个比较,串长1800的test data 5快15倍以上,test data 6快8倍左右。其加速与字典大小、字典前缀大小成正比。字典越长,字典串前缀越长,加速比越高。
另,标程都是用DP来做的,事实上此题用DFS更快。此处用的是DFS。
/*
ID: blackco3
TASK: prefix
LANG: C++
*/
#include <iostream>
#include <memory.h>
#include <windows.h>
using namespace std;
#define _max_seq_len_ 200100
#define _max_dict_ 200
#define _max_dstr_len_ 20
char sequence[_max_seq_len_] ;
int seq_size ;
struct t_tries {
int is_word ;
t_tries *next[26] ;
t_tries():is_word(0){ memset( next, 0, sizeof(next) ); };
} tries_buf[_max_dict_+1] ;
void set_trie( char *cstr ){
static t_tries *p_tri_tail=tries_buf+1 ;
t_tries *p_tri=tries_buf ;
for( char *pc=cstr; *pc!=-1; p_tri=p_tri->next[*pc], pc++) {
if( !p_tri->next[*pc] ){
p_tri->next[*pc]=(p_tri_tail++);
}
}
p_tri->is_word = true ;
}
void clear_chars( char *str ){
for( ; *str!='\0'; str++ )
*str -= 'A' ;
*str = -1 ;
}
int searched[_max_seq_len_], len_prefix ;
char *stk[_max_seq_len_], **top=stk ;
int get_prefix() {
memset( searched, 0, sizeof(searched) );
*(top++)=sequence, searched[0]=1 ;
do{
register t_tries *p_trie=tries_buf ;
register char *pc=*(--top) ;
do{
p_trie=p_trie->next[*pc] ;
if( !p_trie )
break ;
if( *(++pc)==-1 ){
if( p_trie->is_word )
return seq_size ;
else
break ;
}
if( p_trie->is_word && !searched[pc-sequence] ){
*(top++) = pc ;
searched[pc-sequence]=1 ;
len_prefix = len_prefix < pc-sequence ? pc-sequence : len_prefix ;
}
}while(true);
}while(top!=stk);
return len_prefix ;
}
int main() {
freopen("prefix.in", "r", stdin);
freopen("prefix.out", "w", stdout);
char cstr[_max_dstr_len_] ;
do {
cin >> cstr ;
if( !strcmp( cstr, "." ) )
break ;
clear_chars( cstr );
set_trie( cstr );
} while( true );
char *p_seq=sequence ;
while ( cin >> p_seq )
p_seq += strlen( p_seq );
seq_size = p_seq-sequence ;
clear_chars( sequence ) ;
cout << get_prefix() << endl ;
return 0;
}