要想到两个点
1)dp[i]表示前i个最少切多少刀变成回文, 那dp[i] = min( dp[k-1] + 1 ) 其中k-i能组成回文 O(n^2)过了
2)所以这里要考虑个问题怎么知道i能跟之前的哪些字符组成回文。
如果枚举的话 第i个字符枚举【跟第1-i-1个字符组成回文】,判断O(n),这样一来n^3就t了。
所以从回文的性质出发,第i个字符能跟哪些凑成回文,我们看第i-1个能跟哪些个凑成回文,比如k'与i-1凑成回文,那我们看a[i]==a[k'-1]就行了。这样就能O(n^2)找到所有回文
1 #include<iostream> 2 #include<vector> 3 #define INF 100000 4 using namespace std; 5 6 string s; 7 char a[1005]; 8 vector<int> hui[1005];//hui[i]里的k指 k到i组成回文 9 int dp[1005];//dp[i]代表前i个字符要切几刀 10 11 int main(){ 12 int t; cin>>t; 13 while(t--){ 14 cin>>s; 15 int n = s.length(); 16 for(int i=0;i<n;i++) a[i+1] = s[i]; 17 for(int i=1;i<=n;i++) dp[i]=INF; 18 19 hui[1].push_back(1);//第一个跟自己组成回文 20 for(int i=2;i<=n;i++){ 21 hui[i].push_back(i);//自己跟自己组成回文 22 if(a[i]==a[i-1]) hui[i].push_back(i-1); 23 for(int j=0;j<hui[i-1].size();j++){//看i的上一个字符,能与哪些字符组成回文 24 int k = hui[i-1][j]; 25 if( a[k-1]==a[i] ) hui[i].push_back(k-1); 26 } 27 } 28 29 dp[0]=-1; 30 dp[1]=0; 31 for(int i=2;i<=n;i++){ 32 for(int j=0;j<hui[i].size();j++) dp[i] = min(dp[i], dp[ hui[i][j]-1 ]+1 ); 33 } 34 35 cout<<dp[n]<<endl; 36 for(int i=1;i<=n;i++) hui[i].clear(); 37 } 38 39 return 0; 40 }