动态DP(求最大回文串子序列)
https://www.nowcoder.com/acm/contest/90/D
题意:给出一串字符,忽略大小写,问去掉最长的回文子序列后还有多长?
解法:求最大回文串子序列长度
动态规划思想
对于任意字符串,如果头尾字符相同,那么字符串的最长子序列等于去掉首尾的字符串的最长子序列加上首尾;如果首尾字符不同,则最长子序列等于去掉头的字符串的最长子序列和去掉尾的字符串的最长子序列的较大者。
因此动态规划的状态转移方程为:
设字符串为str,长度为n,p[i][j]表示第i到第j个字符间的子序列的个数(i<=j),则:
状态初始条件:dp[i][i]=1 (i=0:n-1)
状态转移方程:dp[i][j]=dp[i+1][j-1] + 2 if(str[i]==str[j])
dp[i][j]=max(dp[i+1][j],dp[i][j-1]) if (str[i]!=str[j])
以下代码中的两层循环变量i,j的顺序可以改变,但必须满足i<=j的条件。
计算dp[i][j]时需要计算dp[i+1][*]或dp[*][j-1],因此i应该从大到小,即递减;j应该从小到大,即递增。
1 //#include<bits/stdc++.h> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstdio> 5 #include <cstring> 6 #include <string> 7 #include <cmath> 8 #include <cstdlib> 9 #include <queue> 10 #include <stack> 11 #include <map> 12 #include <vector> 13 #include <set> 14 15 using namespace std; 16 typedef long long LL; 17 typedef pair<int, int> pii; 18 const int INF = 0x7fffffff; 19 const int maxn = 1300; 20 char str[maxn]; 21 int dp[maxn][maxn]; 22 int n; 23 24 int solve() { 25 // cout << n << endl; 26 for(int j = 0; j < n; j++) { 27 dp[j][j] = 1; 28 for(int i = j - 1; i >= 0; i--) { 29 if(str[i] == str[j]) 30 dp[i][j] = dp[i+1][j-1] + 2; 31 else 32 dp[i][j] = max(dp[i+1][j], dp[i][j-1]); 33 } 34 } 35 // cout << dp[0][n-1]; 36 return dp[0][n-1]; 37 } 38 39 int main(){ 40 #ifdef local 41 freopen("case.in", "r", stdin); 42 #endif 43 while(~scanf("%s", str)) { 44 n = strlen(str); 45 for(int i = 0; i < n; i++) 46 str[i] = tolower(str[i]); 47 memset(dp, 0, sizeof(dp)); 48 // cout << n << endl; 49 int ans = n - solve(); 50 printf("%d\n", ans); 51 } 52 return 0; 53 }