回文串+回溯法 URAL 1635 Mnemonics and Palindromes

 

题目传送门

 1 /*  2  题意:给出一个长为n的仅由小写英文字母组成的字符串,求它的回文串划分的元素的最小个数,并按顺序输出此划分方案  3  回文串+回溯:dp[i] 表示前i+1个字符(从0开始)最少需要划分的数量,最大值是i+1,即单个回文串;  4  之前设置ok[j][j+i] 判断从j到j+i的字符是否为回文串(注意两个for的顺序,为满足ok[j][j+i] = ok[j+1][j+i-1])  5  最后枚举找到最优划分点,用pre[i]记录前一个位置,print函数 输出空格  6 */  7 #include <cstdio>  8 #include <iostream>  9 #include <algorithm> 10 #include <cmath> 11 #include <cstring> 12 using namespace std; 13 14 const int MAXN = 4e3 + 10; 15 const int INF = 0x3f3f3f3f; 16 int dp[MAXN]; 17 int pre[MAXN]; 18 bool ok[MAXN][MAXN]; 19 char s[MAXN]; 20 21 void print(int p) 22 { 23 if (pre[p] == -1) 24  { 25 for (int i=0; i<=p; ++i) printf ("%c", s[i]); 26  } 27 else 28  { 29 print (pre[p]); printf (" "); 30 for (int i=pre[p]+1; i<=p; ++i) printf ("%c", s[i]); 31  } 32 } 33 34 void work(void) 35 { 36 int len = strlen (s); 37 38 for (int i=0; i<len; ++i) 39  { 40 for (int j=0; j+i<len; ++j) 41  { 42 if (i == 0) ok[j][j+i] = true; 43 else if (i == 1) ok[j][i+j] = (s[j] == s[j+i]); 44 else if (s[j] == s[j+i]) ok[j][j+i] = ok[j+1][j+i-1]; 45  } 46  } 47 48 for (int i=0; i<len; ++i) 49  { 50 dp[i] = i + 1; pre[i] = i - 1; 51 if (ok[0][i]) {dp[i] = 1; pre[i] = -1; continue;} 52 for (int j=i-1; j>=0; --j) 53  { 54 if (ok[j+1][i]) 55  { 56 if (dp[i] > dp[j] + 1) 57  { 58 dp[i] = dp[j] + 1; pre[i] = j; 59  } 60  } 61  } 62  } 63 64 printf ("%d\n", dp[len-1]); 65 print (len-1); puts (""); 66 } 67 68 int main(void) //URAL 1635 Mnemonics and Palindromes 69 { 70 //freopen ("P.in", "r", stdin); 71 72 while (scanf ("%s", s) == 1) 73  { 74 memset (ok, false, sizeof (ok)); 75 memset (dp, 0, sizeof (dp)); 76 memset (pre, 0, sizeof (pre)); 77 78  work (); 79  } 80 81 return 0; 82 }

 

你可能感兴趣的:(ROM)