DP,简单的回文词问题。有两种做法!
第一种做法是用LCS来做。因为Maxlen = 5000;所以要用滚动数组,其实我用short型也能过~~
#include <iostream> #include <string.h> using namespace std; short dp[2][5001]; int main() { string s,cs; int i,j,n,e; while(cin>>n) { e = 0; cin>>s; for(i = n-1;i >= 0;i --) cs += s[i]; memset(dp,0,sizeof(dp)); for(i = 1;i <= n;i ++) { e = 1 - e; for(j = 1;j <= n;j ++) { if(s[i-1] == cs[j-1]) dp[e][j] = dp[1-e][j-1] + 1 ; else dp[e][j] = max(dp[1-e][j],dp[e][j-1]); } } cout<<n - dp[e][n]<<endl; cs.clear(); } return 0; }
第二种的Dp做法:opt[i][j]中,i 代表的是 长度,j 代表的是 起点·。决策时分类处理,如果前后两段的字符不同,就比较在前面加字符消去和后面加字符消除的两种情况,然后加一。
如果相同的话,就赋值为前后消除
min(opt[L-1,i]+1,opt[L-1,i+1]+1) (s[i]<>s[i+L])
opt[L,i]=opt[L-2,i+1]) (s[i]=s[i+L])
这是一种很典型的DP。二维dp很好玩~~
依旧用滚动数组。
#include <iostream> #include <string.h> using namespace std; short dp[3][5001]; int main() { int i,j,n,k0,k1,k2,tmp; string s; while(cin>>n) { cin>>s; memset(dp,0,sizeof(dp)); k0 = 0;k1 = 1;k2 = 2; for(i = 2;i <= n;i ++){ for(j = 0;j <= n -i;j ++) { dp[k2][j] = min(dp[k1][j],dp[k1][j+1]) + 1; if(s[j] == s[j+i-1]) dp[k2][j] = dp[k0][j+1]; } tmp = k0; k0 = k1;k1 = k2;k2 = tmp; } cout<<dp[k1][0]<<endl; } return 0; }