題目鏈接:
http://acm.hdu.edu.cn/showproblem.php?pid=4628
題目大意:
給出一個字符串,每次你可以擦除一個迴文子串,問至少需要多少步可以將該字符串全部擦除。
解題思路:
由於字符串的長度最多是16,所以可以採用狀態壓縮來解這個題目。
dp[i][j]:表示第i步時,狀態j是否出現。
源代碼:
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<math.h>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
char ch[20];
int dp[20][70000];
string s;
int state[70000];
int cnt;
int ok(string t) //判斷字符串是否迴文
{
int i,j;
i=0;
j=t.length()-1;
while(i<j)
{
if(t[i]!=t[j]) return 0;
else
{
i++; j--;
}
}
return 1;
}
string zifu(int k) //將狀態數轉成對應的字符串
{
int len;
string s1;
len=s.length();
s1="";
for(int i=0;i<len;i++)
{
if(k%2==1) s1+=s[i];
k=k/2;
}
return s1;
}
void init(string s) //找出所有的有效狀態
{
int k,len,i;
string s1;
len=s.length();
k=(1<<len)-1; //所有狀態的總個數
memset(state,0,sizeof(state));
cnt=0;
for(i=1;i<=k;i++)
{
s1=zifu(i);
if(ok(s1))
{
state[cnt++]=i;
}
}
return;
}
bool cmp(int x,int y)
{
return x>y;
}
int main()
{
freopen("in.txt","r",stdin);
int cs,i,d,j,k;
scanf("%d",&cs);
while(cs--)
{
scanf("%s",ch);
s=ch;
i=s.length();
d=(1<<i)-1;
init(s);
sort(state,state+cnt,cmp);
if(state[0]==d)
{
printf("1\n");
continue;
}
memset(dp,0,sizeof(dp));
//枚舉第一行出現的有效狀態
for(i=0;i<cnt;i++)
{
dp[1][state[i]]=1;
}
int flag=0;
for(i=2;;i++) //枚舉接下來的行狀態
{
for(j=1;j<=d;j++) //枚舉上一行的狀態
{
if(dp[i-1][j]==0) continue;
for(k=0;k<cnt;k++) //枚舉當前行可以擦除的狀態
{
if((state[k]&j)==0) //所取狀態與已得狀態不衝突
dp[i][state[k]+j]=1;
}
if(dp[i][d]==1)
{
printf("%d\n",i);
flag=1;
break;
}
}
if(flag) break;
}
}
return 0;
}