题意:给你几个字符串,你每次删除的字母要按顺序看是一个回文串。求最少几次就可以把它删完。
思路:状态压缩dp。写个函数判断一个状态含有的1是否按顺序对应字符串的位置的字母是一个回文串。预处理所有是回文串的状态,否则会TLE。然后直接枚举删之前的状态和删完之后的状态,判断删的是不是回文串。
第一次用异或^,具体见代码注释,应该不难理解。
AC代码:
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
const int mo=1e8;
const int mx=1<<16;
const int inf=0x3f3f3f3f;
int n,m,ans,k,T,num;
char s[20];
int dp[mx];
int zt[mx];
bool b[mx];
void init()
{
memset(dp,-1,sizeof(dp));
memset(b,0,sizeof(b));
num=0;
}
bool jud(int i)
{
if(i==0) return 1;
int j=0;
int k=n-1;
while(j<k)//直接暴力判断是不是回文串
{
while(!(1<<j&i)) {j++;}
while(!(1<<k&i)) {k--;}
if(s[j]!=s[k]) return 0;
{j++;}
{k--;}
}
return 1;
}
int main() {
int t,i,j,k,l,q,x,y,h;
int cas=1,flag,f1;
while(scanf("%d",&T)!=EOF)
{
while(T--){
scanf("%s",s);
n=strlen(s);
m=1<<n;
init();
for(i=0;i<m;i++) if(jud(i)) b[i]=1;//一定要预处理出合法的状态
dp[0]=0;
for(i=0;i<m;i++)
{
for(k=(i+1)|i;k<m;k=(k+1)|i)//枚举包含i状态的状态,因为你删除原串中的回文串就相当于把i状态的某些位置的0变成1,也就是变成包含i状态的k状态
{
if (b[k^i]&&dp[i]!=-1)//k^i就是你删除的那个串,想想是不是
{if (dp[k]<0)dp[k]=dp[i]+1;
else dp[k]=min(dp[k],dp[i]+1);
}
}
}
printf("%d\n",dp[m-1]);
}
}
return 0;
}