这个题是DP的经典题目,主要思想及状态转移在于:一个位置需要切割的刀数,等于从之前到他最长的回文序列,之前的那个元素切割的刀数+1,或者如果他与之前的无法构成回文序列,则等于之前那个位置所需要切割的刀数+1
DP太不熟练了......真的需要多练了...
#include <iostream>
#include <cstring>
using namespace std;
int judgethereverse(char s[],int start,int end)//这里需要采用线性judge 找寻第[start,end]
//采用 计算机下标
{
//假设abcdefg 找寻 都2到5 2到6位
// 0123456
int length = end-start+1;
if(length%2==0)//如果是偶数位
{
int temp = (start+end+1)/2;
int count = 0;
for(int i=start;i<temp;i++)//
{
// printf("%c\t%c\n",s[i],s[end-count]);
if(s[i]!=s[end-count])
{
return 0;
}
count ++;
}
return 1;
}
else if(length%2!=0)//如果是奇数位abcdcba
// 0123456
{
int temp = (start+end)/2;
int count = 0;
for(int i=start;i<temp;i++)
{
// printf("%c\t%c\n",s[i],s[end-count]);
if(s[i]!=s[end-count])
{
return 0;
}
count ++;
}
return 1;
}
}
int main(void)
{
int t;
scanf("%d\n",&t);
while(t--)
{
char s[1005];
scanf("%s",s);
int lens = strlen(s);
int dp[1005];//表示这个位置需要的切割数
for(int i=1;i<=lens;i++)
{
dp[i] = i-1;//这个位置默认需要的切割数
}
for(int i=0;i<lens;i++)
{
if(judgethereverse(s,0,i)==1)
{
dp[i+1] = 0;
}
else
{
dp[i+1] = dp[i] + 1;
for(int j=1;j<i;j++)
{
if(judgethereverse(s,j,i)==1)
{
dp[i+1] = dp[j] + 1; //这里为什么是dp j 因为这里角标差了1 所以不是j-1
break;
}
}
}
}
// for(int i=1;i<=lens;i++)
// {
// printf("%d",dp[i]);
// }
printf("%d\n",dp[lens]);
/*如果能从0位开始构成回文 则那个位置的切割数是0
如果不能 则从第1位开始找,有没有能和这个位置构成回文的
如果有则找到这些回文中“长度最长的”默认这一段切割掉 此时这个位置的所需切割数
等于这个位置之前的切割数+1
如果在这些里也没有找到回文的 则这个位置的长度等于其前一位的切割长度+1
总结:一个位置的切割长度
回文要么存在于从第一位开始到某一位
要么存在于 顺序遍历 往回的查找即 2-1 3-1 -32 4-1 4-2 4-3 4-4中
一个位置的切割回文数情况 等于其前边的回文数情况+1 与 它所构成回文序列之前的 数字+1 之间的最小值
*/
}
}//dynamic Programming