poj 3280 Cheapest Palindrome 最优子结构,动态规划
对于 串 Str(I,J)构成 回文串,
一,其可以由 子串Str(I+1,J)构成的回文串 D(I+1,J) 再通过在最右添加字符S(I)构成
二,也可以由 字串Str(I, J-1)构成的回文串 D(I, J-1) 再通过在最左边添加字符 S(J)构成
三,当 S(I) == S(J)时,两个边界不花费总是最优,我们可以由 子串Str(I+1,J-1)构成的回文串 D(I+1,J+1)构成
所以,可以定义状态 DP(I,J)表示 串 Str(i,j)构成回文串最小花费
转移策略:
一, DP(I,J) = Min { DP(I+1,J)+cost(i), DP(I,J-1)+cost(j)}
若此时 Str(i)== Str(j)
二,DP(I,J) = Min{ DP(I,J),DP(I+1,J-1)}
对于代码实现, 因为我们所球 DP(i, j) 仅仅由 DP(I+1,J),DP(I,J-1),DP(I+1,J+1)
三种情况决定,对于当前所求区间(I,J),则我们必须知道已包含 I 或 J 的部分,且必须先求得小区间后再求大区间,
所以我们可以先枚举 区间右边界J, 然后从小到大枚举左边界I,所以I取值范围为【J-1,0】
当 J-I = 1时,因为 I+1 = 1,J-1 = 0 ,此时 区间(1,0)不合法,我们可以通过初始化DP数组为0,来表示。
解题代码
View Code
#include<stdio.h> #include<stdlib.h> #include<string.h> #define MIN(a,b) (a)<(b)?(a):(b) const int N = 2013; int cost[27], dp[N][N]; int n, m; char s[N]; int main() { while( ~scanf("%d%d", &n,&m) ) { scanf("%s", s ); char ch[2]; int add,del; for(int i = 0; i < n; i++) { scanf("%s %d %d", ch, &add, &del ); cost[ ch[0]-'a' ] = MIN( add, del ); } memset( dp, 0, sizeof(dp) ); for(int j = 1; j < m; j++) { for(int i = j-1; i >= 0; i-- ) { dp[i][j] = MIN( dp[i+1][j]+cost[ s[i]-'a' ], dp[i][j-1]+cost[ s[j]-'a' ] ); if( s[i] == s[j] ) dp[i][j] = MIN( dp[i][j], dp[i+1][j-1] ); } } printf("%d\n", dp[0][m-1] ); } return 0; }