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;
}

 

  

posted @ 2013-01-13 13:50  yefeng1627  阅读(158)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor