USACO Training Section 2.3 Longest Prefix (Tries实现)

英文原题  中文题译

大意:给定一个单词表和一个字串,找字串的可被给定单词表表示的最长前缀的长度。

之前在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;
}

你可能感兴趣的:(C++,c,C#,asp)