题意:
一个字符串,每次可以删掉一个子序列,且这个子序列必须构成回文串,求全部删完的最少次数。
题解:
枚举要删除的子序列,剩下的继续删除,记下每个部分的最少删除次数。
代码写得很挫……
//Time:125ms
//Memory:560KB
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <map>
#define MAXN 20
#define MAXM (1<<16)
#define FI first
#define SE second
#define INF 1000000007
#define MP(x,y) make_pair((x),(y))
using namespace std;
struct _node
{
char str[MAXN];
int pos[MAXN];
int len;
};
int pre[MAXM];
int dp[MAXN][MAXN];
pair<int,int> fa[MAXN][MAXN];
void cal(char *s,int len,int x,int y)
{
for(int i=x;i>=0;--i)
for(int j=y;j<len;++j)
if(i!=x||j!=y)
{
dp[i][j]=0;
if(i<x&&dp[i+1][j]>dp[i][j]) dp[i][j]=dp[i+1][j],fa[i][j]=MP(i+1,j);
if(j>y&&dp[i][j-1]>dp[i][j]) dp[i][j]=dp[i][j-1],fa[i][j]=MP(i,j-1);
if(i<x&&j>y&&s[i]==s[j])
if(dp[i+1][j-1]+2>dp[i][j])
dp[i][j]=dp[i+1][j-1]+2,fa[i][j]=MP(0,-1);
}
}
int solve(_node no)
{
_node tno;
int ans=INF,tmp;
pair<int,int> now;
bool vi[MAXN]={0};
for(int i=0;i<no.len;++i)
{
for(int j=i;j<no.len;++j)
{
if(no.str[j]!=no.str[i]) continue;
memset(dp,0,sizeof(dp));
memset(vi,0,sizeof(vi));
dp[i][j]=(i!=j?2:1);
fa[i][j]=MP(-1,-1);
cal(no.str,no.len,i,i);
now=MP(0,no.len-1);
vi[i]=vi[j]=1;
while(now.FI!=-1)
{
if(fa[now.FI][now.SE]==MP(0,-1)) vi[now.FI]=1,vi[now.SE]=1,++now.FI,--now.SE;
else now=fa[now.FI][now.SE];
}
tmp=0;
tno.len=0;
for(int i=0;i<no.len;++i)
if(!vi[i])
{
tno.str[tno.len]=no.str[i];
tno.pos[tno.len++]=no.pos[i];
tmp|=1<<no.pos[i];
}
if(pre[tmp]<INF)
ans=min(ans,1+pre[tmp]);
else ans=min(ans,1+solve(tno));
}
}
tmp=0;
for(int i=0;i<no.len;++i)
tmp|=1<<(no.pos[i]);
pre[tmp]=min(pre[tmp],ans);
return ans;
}
int main()
{
//freopen("/home/moor/Code/input","r",stdin);
int ncase;
_node no;
scanf("%d",&ncase);
while(ncase--)
{
scanf("%s",no.str);
memset(pre,0x3f,sizeof(pre));
pre[0]=0;
no.len=strlen(no.str);
for(int i=0;i<no.len;++i) no.pos[i]=i;
printf("%d\n",solve(no));
}
return 0;
}