状压dp删回文串,

You heart broke into pieces.My string broke into pieces.But you will recover one day,and my string will never go back. 
Given a string s.We can erase a subsequence of it if this subsequence is palindrome in one step. We should take as few steps as possible to erase the whole sequence.How many steps do we need? 
For example, we can erase abcba from axbyczbea and get xyze in one step.

Input

The first line contains integer T,denote the number of the test cases. Then T lines follows,each line contains the string s (1<= length of s <= 16). 
T<=10.

Output

For each test cases,print the answer in a line.

Sample Input

2
aa
abb

Sample Output

1
2

题意:

给一个字符串,长度<=16,每次去掉一个回文串,可以中不连续的,问最少用多少次把所给的串都去掉。

思路:

状态dp,分别用0和1表示原来字符串某个位置字符串是否去掉。0对应的是去掉的,1对应的是保留的。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
char s[25];
int dp[1<<17];
int len;
int sta;
int init(int x){            //判断某个状态对应的字符串的回文串的大小,如果字符串全部回文,返回1,否则返回字符串的长度
    int ss[17]={0};
    int ans=0;
    for(int i=0;i<=len;i++)
        if(x&(1<<i))
            ss[ans++]=i;
            ans--;
    for(int j=0;j<ans/2;j++) //从中点向两边看,是否回文,如果发现不回文的任意两个个字母,就返回状态x的字符串长度,因为最多这么多步把该字符串删掉。
        if(s[ss[j]]!=s[ss[ans-j]])
            return ans;
            return 1;
}
void solve(){
    len=strlen(s);
    sta=1<<len;//初始的状态是11111……111,就是全部都存在
    sta--;
    for(int i=1;i<=sta;i++){ //枚举各种状态,对其进行初始化
        dp[i]=init(i);//对每一个dp初始化
        for(int k=i;k>0;k=(k-1)&i) //枚举每一个状态的子状态
            dp[i]=min(dp[i],dp[k]+dp[k^i]);//子状态及其补集
    }
}
int main(){
    int T;
    cin>>T;
    while(T--){
    memset(dp,0,sizeof(dp));
    cin>>s;
    solve();
    cout<<dp[sta]<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40859951/article/details/82938029
今日推荐