poj3280(区间dp)

 

题目连接:http://poj.org/problem?id=3280

题意:给定一个长度为m(m<=2000)的小写字母字符串,在给定组成该字符串的n(n<=26)个字符的添加和删除费用,求使原字符串变为回文串的最小费用。

分析:首先明确,删除一个字母和增加一个字母是等价的,如果删除一个字符一个字符使得原字符串变成回文,那么必定可以增加一个字符使原字符串变成回文,因此对于删除和增加操作去费用最少的即可。

dp[i][j]表示区间i~j形成回文串最少费用,则:

dp[i][j] = min(dp[i+1][j]+cost[str[i]-'a'], dp[i][j-1]+cost[str[j]-'a']);

 if(str[i] == str[j])dp[i][j] = min(dp[i][j],dp[i+1][j-1]);

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 100000000
#define inf 0x3f3f3f3f
#define eps 1e-9
#define N 100010
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int cost[30],dp[2110][2110];
char s[10],str[2100];
int dfs(int l,int r)
{
    if(dp[l][r]!=-1)return dp[l][r];
    if(l>=r)return 0;
    int temp=inf;
    if(str[l]==str[r])
        temp=min(temp,dfs(l+1,r-1));
    temp=min(temp,dfs(l+1,r)+cost[str[l]-'a']);
    temp=min(temp,dfs(l,r-1)+cost[str[r]-'a']);
    return dp[l][r]=temp;
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)>0)
    {
        scanf("%s",str+1);
        for(int i=1;i<=n;i++)
        {
            int add,det;
            scanf("%s%d%d",s,&add,&det);
            cost[s[0]-'a']=min(add,det);
        }
        FILL(dp,-1);
        printf("%d\n",dfs(1,m));

    }
}
View Code

 

posted on 2015-02-01 22:46  lienus  阅读(194)  评论(0编辑  收藏  举报

导航