这个题大意是给你一个字符串,每次你可以删除其回文子串,问你删除整个子串最少需要多少步。
思路:
1、最开始算出所有的回文串,我是直接枚举的,以位运算表示满足要求的回文子串状态
2、状态压缩,因为字符串长度不超过16,所以可以用数字的位表示。
3、搜索答案,我用的是背包的思想
最开始用DFS记忆化写的,一直超时,其实超时的原因是因为我判断当前字符串是否满足当前所枚举的回文串的时候是用循环的。后来发现其实可以用异或运算然后判断是否等于其差值得到,从而节省了时间,顺利过了~
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=1<<16;
const int inf=1<<29;
int isp[maxn],dp[maxn],len,n,cur;
char str[20];
void Init()
{
cur=0;
n=(1<<len)-1;
for(int i=1;i<=n;i++)
{
int j=0,k=len-1;
bool is=true;
while(1)
{
for(;j<len;j++)
if(i&(1<<j))
break;
for(;k>=0;k--)
if(i&(1<<k))
break;
if(str[j]!=str[k])
{
is=false;
break;
}
j++,k--;
if(j>k)
break;
}
if(is)
isp[cur++]=i;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",str);
len=strlen(str);
Init();
if(cur==len)
{
printf("%d\n",len);
continue;
}
memset(dp,0x7f,sizeof(dp));
dp[0]=0;
for(int i=cur-1;i>=0;i--)
{
for(int j=n;j-isp[i]>=0;j--)
if(j^isp[i]==j-isp[i])
dp[j]=min(dp[j],dp[j^isp[i]]+1);
if(dp[n]==1||dp[n]==2)
break;
}
printf("%d\n",dp[n]);
}
return 0;
}