POJ 8471 切割回文 【dp】【北大ACM/ICPC竞赛训练】

 要想到两个点

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 }
原文地址:https://www.cnblogs.com/ZhenghangHu/p/9386435.html