NOI 题库 8471 题解
8471 切割回文
- 描述
-
阿福最近对回文串产生了非常浓厚的兴趣。
如果一个字符串从左往右看和从右往左看完全相同的话,那么就认为这个串是一个回文串。例如,“abcaacba”是一个回文串,“abcaaba”则不是一个回文串。
阿福现在强迫症发作,看到什么字符串都想要把它变成回文的。阿福可以通过切割字符串,使得切割完之后得到的子串都是回文的。
现在阿福想知道他最少切割多少次就可以达到目的。例如,对于字符串“abaacca”,最少切割一次,就可以得到“aba”和“acca”这两个回文子串。
- 输入
- 输入的第一行是一个整数 T (T <= 20) ,表示一共有 T 组数据。
接下来的 T 行,每一行都包含了一个长度不超过的 1000 的字符串,且字符串只包含了小写字母。 - 输出
- 对于每组数据,输出一行。该行包含一个整数,表示阿福最少切割的次数,使得切割完得到的子串都是回文的。
- 样例输入
-
3 abaacca abcd abcba
- 样例输出
-
1 3 0
- 提示
- 对于第一组样例,阿福最少切割 1 次,将原串切割为“aba”和“acca”两个回文子串。
对于第二组样例,阿福最少切割 3 次,将原串切割为“a”、“b”、“c”、“d”这四个回文子串。
对于第三组样例,阿福不需要切割,原串本身就是一个回文串。 - 划分型DP
- f[ i ] 表示前 i 个需要切割的次数
-
1 #include "bits/stdc++.h" 2 3 using namespace std ; 4 const int maxN = 1100 ; 5 const int INF = 2147483647 ; 6 7 int Judge [ maxN ][ maxN ] ; 8 char s[ maxN ] ; 9 int f[ maxN ] ; 10 11 inline int gmin ( int x , int y ) { return x < y ? x : y ; } 12 13 inline void Init ( const int n ) { 14 for ( int i=1 ; i<=n ; ++i ) Judge[ i ][ i ] = true ; 15 for(int i=1 ; i<=n ; ++i ) { 16 for(int L=0 ; i-L>=1 && i+L<=n ; ++L ) { 17 if ( s [ i - L ] != s [ i + L ] ) break; 18 else Judge[ i - L ][ i + L ] = true ; 19 } 20 for(int L=0 ; i-L>=1 && i+L+1<=n ; ++L ) { 21 if ( s [ i - L ] != s [ i + L + 1 ] ) break; 22 else Judge[ i - L ][ i + L + 1 ] = true ; 23 } 24 } 25 } 26 27 int main ( ) { 28 int T ; 29 scanf ( "%d" , &T ) ; 30 while ( T-- ) { 31 memset ( f , 0x7f , sizeof ( f ) ) ; 32 memset ( Judge , false , sizeof ( Judge ) ) ; 33 scanf ( "%s" , s + 1 ) ; 34 int Len = strlen ( s + 1 ) ; 35 Init ( Len ) ; 36 37 for ( int i=1 ; i<=Len ; ++i ) { 38 if ( Judge [ 1 ][ i ] ) {f[ i ] = 0 ; continue ;} 39 for ( int j=1 ; j<i ; ++j ) { 40 if ( Judge[ j + 1 ][ i ] ) { 41 f[ i ] = gmin ( f[ i ] , f[ j ] + 1 ) ; 42 } 43 } 44 } 45 printf ( "%d\n" , f[ Len ] ) ; 46 } 47 return 0 ; 48 }
2016-10-27 12:50:52