longpo的回文 题解

题目链接

题目大意

有一个字符串和\(m\)个操作,每个操作都有一定的代价,判断是否能通过一系列操作使该字符串变成回文串。并求出最小代价。

分析

  • \(Floyed\)

给出这些操作,会发现有些操作是完全没有用的(因为有更好的组合可以达到此目的),所以我们可以先跑一遍\(Floyed\),求出这26个字母与空格互相转换的最小代价。

转换为空格就是删除操作,从空格转换来就是添加操作

// 我们这里使用0~25表示a~z 用26表示空格
for ( int i = 0 ; i < 27 ; i ++ )
		for ( int j = 0 ; j < 27 ; j ++ ) g[ i ][ j ] = inf ;
	for ( int i = 0 ; i < 27 ; i ++ ) g[ i ][ i ] = 0 ;
	for ( int i = 1 ; i <= m ; i ++ ) {
		char tmp[ 10 ] , a[ 3 ] , b[ 3 ] ; int v ;
		scanf ( "%s" , tmp + 1 ) ;
		if ( tmp[ 1 ] == 'a' ) {
			scanf ( "%s%d" , a , &v ) ;
			int t = a[ 0 ] - 'a' ;
			g[ 26 ][ t ] = min ( g[ 26 ][ t ] , ( ll ) v ) ;
		}
		else if ( tmp[ 1 ] == 'e' ) {
			scanf ( "%s%d" , a , &v ) ;
			int t = a[ 0 ] - 'a' ;
			g[ t ][ 26 ] = min ( g[ 26 ][ t ] , ( ll ) v ) ;
		}
		else {
			scanf ( "%s%s%d" , a , b , &v ) ;
			int t1 = a[ 0 ] - 'a' , t2 = b[ 0 ] - 'a' ;
			g[ t1 ][ t2 ] = min ( g[ t1 ][ t2 ] , ( ll ) v ) ;
		}
	}
	for ( int k = 0 ; k < 27 ; k ++ ) {
		for ( int i = 0 ; i < 27 ; i ++ ) {
			for ( int j = 0 ; j < 27 ; j ++ ) {
				g[ i ][ j ] = min ( g[ i ][ k ] + g[ k ][ j ] , g[ i ][ j ] ) ;
			}
		}
	}
  • 然后我们采用记忆化搜索

因为要构成回文串,所以我们首尾搜索,每次搜索暴力枚举首尾变成哪个字符(或空格),直到最后搜完

为了防止超时,采用记忆化

inline ll solve ( int st , int ed ) {
	if ( st >= ed ) return 0 ; // 结束
	if ( dp[ st ][ ed ] != -1 ) return dp[ st ][ ed ] ; // 记忆化
	ll ret = inf ;
	int a = val[ st ] , b = val[ ed ] ;
	for ( int i = 0 ; i < 27 ; i ++ ) { // 暴力枚举每个字符
		if ( g[ a ][ i ] + g[ b ][ i ] < inf ) 
			ret = min ( ret , g[ a ][ i ] + g[ b ][ i ] + solve ( st + 1 , ed - 1 ) ) ;
		if ( g[ a ][ i ] + g[ 26 ][ i ] < inf )
			ret = min ( ret , g[ a ][ i ] + g[ 26 ][ i ] + solve ( st + 1 , ed ) ) ;
		if ( g[ 26 ][ i ] + g[ b ][ i ] < inf )
			ret = min ( ret , g[ 26 ][ i ] + g[ b ][ i ] + solve ( st , ed - 1 ) ) ;
	}
	return dp[ st ][ ed ] = ret ;
}
posted @ 2020-07-22 11:35  hulean  阅读(123)  评论(0编辑  收藏  举报