回文串即,一个串反过来读也是他本身的串就叫做回文串。
回文串的判定:
bool isPalindrome(char *s)
{
int len=strlen(s);
int l=0;
int r=len-1;
while(l<r) //相等不用判定
{
if(s[l]==s[r])
l++,r--;
else
return false;
}
return true;
}
回文串问题:
1.一个字符串分解成多串回文序列,求最小的分解序列数
该问题规模较小,考虑状态压缩,使用dp,整个串当作一个集合,查询其中每个子集合是否是一个回文序列,如果是回文序列可以减掉该串进行动态规划。
char s[maxn];
int len;
bool ispalindrome[maxm];
ll dp[maxm];
bool judge(int i)
{
int l=0;
int r=len-1;
while(l<r)
{
while((i&(1<<l))==0)
l++;
while((i&(1<<r))==0)
r--;
if(s[l]!=s[r])
return false;
else
l++,r--;
}
return true;
}
void init()
{
memset(dp,-1,sizeof(dp));
dp[0]=0;
for(int i=1;i<=(1<<len)-1;i++)
{
if(judge(i)) //判定是否是回文串
ispalindrome[i]=true;
else
ispalindrome[i]=false;
}
}
ll scdp(int state)
{
if(dp[state]!=-1)
return dp[state];
ll temp=inf;
for(int i=state;i>0;i=(state&(i-1)) )
{
if(ispalindrome[i])
temp=min(temp,scdp(state-i)+1);
}
return dp[state]=temp;
}
2.一个字符串分解成多串回文串,求最小的分解串数
每增加一个字符,就dp该字符增加后所需最小的回文串数,注意判定回文串的时候有一个结论,当前新加上去的字符i,能够组成的回文串一定是在前一个能组成的回文串基础上进行的。三种情况:1.i本身单独回文 2.前一个i-1有的回文串基础上加上 3.前一个回文串i-1的基础上加上i和回文串的前一个字符。
for(int i=1;i<=len;i++)
{
dp[i]=dp[i-1]+1;
pos[i].push_back(i-1); //记录回文串的头标记位置
for(int j=0;j<pos[i-1].size();j++)
{
int p=pos[i-1][j];
if(isPalindrome(p-1,i-1)==true)
{
pos[i].push_back(p-1);
dp[i]=min(dp[i],dp[p-1]+1);
}
if(isPalindrome(p,i-1)==true)
{
pos[i].push_back(p);
dp[i]=min(dp[i],dp[p]+1);
}
}
}