Pieces
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
题意:
给定一个串,每次可以删除一个回文子串,问把全串删干净的最少次数。
这里的字串任意选,不要求连续。
思路: 看到S<=16可能条件反应可以状态压缩了,仔细一看还真是,对于每个状态可以枚举子集串,枚举子串是老生常谈的
算法了,这里详细写一下。比如 abcd 有4个数码,对于每个数码可以选也可以不选,一共2^4种,“” ,a ,b ,c ,d',ab ....abcd
当然了,空子串排除,那么总共的字串是2^串长-1 ,将串“映射”成数字,比如a-->1000 ,b--->0100 ,c-->0010 ,ad--1001 ,
adcd-->1111 ,这样做即可把所有的子串枚举出来。但是此题要求字串为回文,这只需要稍加判断即可,啰嗦一句,其实STL
熟悉了是比较方便编码的,不要太过于排斥STL 。
DP的部分就是个类似背包了 。注意代码里的一点 j&=i ,j表示字串 ,I 表示母串 ,如果注释j&=i ,会TL 。
举个例子吧。比如i=100000 , 事实上字串只有100000 。只需要枚举100000即可, 如10100 ,只需枚举10100 ,10000 ,00100
即可,j=j&i 起到加速作用(不要太过于纠结这里,可能上厕所的时候就恍然大悟了), 可以用笔画一下。
#include <iostream> #include <string.h> #include <string> #include <algorithm> #include <stdio.h> #include <queue> #include <set> #include <limits.h> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std ; struct Me{ string str ; int is_palindrome[(1<<16)+10] ; int dp[(1<<16)+10] ; Me(){} Me(string s):str(s){} void get_is_palindrom(){ memset(is_palindrome,0,sizeof(is_palindrome)) ; for(int i=1;i<(1<<str.length());i++){ vector<int>vec ; vec.clear() ; for(int j=0;j<str.length();j++){ if(i&(1<<j)) vec.push_back(j) ; } int k ; for(k=0;k<vec.size();k++){ if(str.at(vec[k])!=str.at(vec[vec.size()-k-1])) break ; } if(k==vec.size()) is_palindrome[i]=1 ; } } void DP(){ get_is_palindrom() ; fill(dp,dp+(1<<str.length()),16) ; dp[0]=0 ; for(int i=1;i<(1<<str.length());i++){ for(int j=i;j>=1;j--){ if(is_palindrome[j]) dp[i]=Min(dp[i],dp[i-j]+1) ; j&=i ; //这个注意
} } } int gao_qi(){ DP() ; return dp[(1<<str.length())-1] ; } }; int main(){ int T ; string s ; cin>>T ; while(T--){ cin>>s ; Me me(s) ; cout<<me.gao_qi()<<endl ; } return 0 ; }
浙公网安备 33010602011771号