POJ3280 Cheapest Palindrome

题目链接:

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16272

题意:

给一个字符串和每个字符的权值,问最小代价通过删除或者增加任意位置字符使得字符变为回文串。

思路:

区间DP,毫无意外的看了题解。具体的话每次增加一个字符,增加代价为头字符和尾字符代价的最小值。当头尾相等时,即data[i]==data[j]时,dp[i][j] =gmin(dp[i+1][j-1])。

算是革新思想的一题。区间DP的关键是大区间化简为小区间,而不是中间区间的更新过程。实际上更新过程因题而异,有的从头,有的从尾;有的遍历中间点,有的只看头尾两点。关键是要理解增添区间的过程,以及区间封装的数值相互影响的关系。说得有些抽象,重点就是大区间化为小区间,其他的灵活处理。

源码:

#include <cstdio>

#include <cmath>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <string>

#include <queue>

using namespace std;

#define gmin(a,b) a<b?a:b

int const MAXN = 2000+5;

int dp[MAXN][MAXN];

int alp[30];

char data[MAXN];

int main()

{

   int n,m;

   while(scanf("%d%d",&n,&m)!=EOF){

       scanf("%s",data);

       getchar();

       char c;

       int t1,t2;

       memset(dp,0,sizeof(dp));

       memset(alp,0,sizeof(alp));

       for(int i=0; i<n; i++){

           scanf("%c %d %d",&c,&t1,&t2);

           alp[c-'a'] = gmin(t1,t2);

           getchar();

//            printf("for i = %d,c= %c,t1 =%d,t2 = %d\n",i,c,t1,t2);

       }

       for(int i=1; i<m; i++){

           for(int j=0; j+i<m; j++){

                dp[j][j+i] = dp[j+1][j+i-1] +alp[data[j]-'a'] + alp[data[j+i]-'a'];

//                for(int k=j+1; k<=j+i; k++){

//                    if(data[k] == data[j])

//                        dp[j][j+i] =gmin(dp[j][j+i],dp[j+1][k-1]+dp[k+1][j+i-1]);

                    dp[j][j+i] =gmin(dp[j][j+i],dp[j+1][j+i]+alp[data[j]-'a']);

                    dp[j][j+i] =gmin(dp[j][j+i],dp[j][j+i-1]+alp[data[j+i]-'a']);

                    if(data[j+i] == data[j])

                        dp[j][j+i] = gmin(dp[j][j+i],dp[j+1][j+i-1]);

//                }

           }

       }

//       for(int i=0; i<m; i++){

//            for(int j=0; j<m; j++)

//                printf("%d",dp[i][j]);

//            printf("\n");

//       }

       printf("%d\n",dp[0][m-1]);

    }

   return 0;

}

你可能感兴趣的:(POJ3280 Cheapest Palindrome)