题目连接http://poj.org/problem?id=1159
这道题原来见过,那时候没学DFS什么的,以为是搜索然后直接暴搜,但是说真的真是没有想到这题竟然是DP,那时候也没学DP就放弃了。。。
这道题的思路就是把整个问题分解成小问题,然后从下往上来求。。。
我们先设一个DP[N][N],它里面是每个i~j变成回文的最小添加量,也就是说我们可以看做DP后已经全部都是回文。
那么DP[1][N]就可以满足一个状态方程
if(STR[1] == STR[N]
I = 1,J = N;
DP[1][N] == DP[I+1][J-1] + 1 (STR[I] == STR[J])
DP[I+1][J]+1 (STR[I] != STR[J] && DP[I+1][J] < DP[I][J-1])
DP[I][J-1]+1 (STR[I] != STR[J] && DP[I+1][J] > DP[I][J-1])
但是如果我们这样写。。。。
for(i = n-1;i >= 0;i--) { for(j = i+1;j < n;j++) { if(str[i] == str[j]) dp[i][j] = dp[(i+1)][j-1]; else dp[i][j] = (dp[(i+1)][j] < dp[(i)][j-1]?dp[i+1][j]:dp[i][j-1])+1; } }
由于数据量比较大 5000所以开数组的话会ME,这是我们就需要用滚动数组。
这段代码中时自底向上,而且只用了俩种i,所以
for(i = n-1;i >= 0;i--) { for(j = i+1;j < n;j++) { if(str[i] == str[j]) dp[i%2][j] = dp[(i+1)%2][j-1]; else dp[i%2][j] = (dp[(i+1)%2][j] < dp[(i)%2][j-1]?dp[(i+1)%2][j]:dp[i%2][j-1])+1; } }
1 for(i = n-1;i >= 0;i--) 2 { 3 for(j = i+1;j < n;j++) 4 { 5 if(str[i] == str[j]) 6 dp[i][j] = dp[(i+1)][j-1]; 7 else 8 dp[i][j] = (dp[(i+1)][j] < dp[(i)][j-1]?dp[i+1][j]:dp[i][j-1])+1; 9 } 10 }
所以代码
View Code
#include <stdio.h> #include <string.h> #define N 5050 int dp[2][N]; int main() { int n,i,j; char str[N]; while(~scanf("%d",&n)) { getchar(); gets(str); memset(dp,0,sizeof(dp)); for(i = n-1;i >= 0;i--) { for(j = i+1;j < n;j++) { if(str[i] == str[j]) dp[i][j] = dp[(i+1)][j-1]; else dp[i][j] = (dp[(i+1)][j] < dp[(i)][j-1]?dp[i+1][j]:dp[i][j-1])+1; } } printf("%d\n",dp[0][n-1]); } return 0; }