[POJ 3280]Cheapest Palindrome[DP]

题目链接: [POJ 3280]Cheapest Palindrome[DP]

题意分析:

有一个长度为m的字符串,全都为小写字母,给出串中每个字母删除和插入的代价,问:要构成回文串,最少需要多少代价?

解题思路:

设dp[i][j]为字符串s[i ~ j]变成回文串需要的最小代价。那么有转移方程:

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

否则 dp[i][j] 由dp[i + 1][j]添加或者删除s[i],由dp[i][j - 1]添加或者删除s[j]得来。前者新增字符为s[i],后者新增字符为s[j],而s[i + 1][j] 和 s[i][j - 1]均已经为回文,所以这么转移。

个人感受:

状态有了,可是我一直纠结内部的具体细节,比如它删了,它添加了,那么后继状态的删除添加不就要考虑前面状态了吗?其实并不用考虑这么多,因为转移二已经把所有的添加删除都考虑了。

具体代码如下:

#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;

const int MAXN = 2e3 + 111;

ll dp[MAXN][MAXN];
char sh[MAXN];
int s[MAXN];
ll ad[30], del[30];

int main()
{
    int n, m; scanf("%d%d%s", &n, &m, sh);
    for (int i = 0; i < m; ++i) s[i] = sh[i] - 'a';
    char c[2];
    int a, b;
    for (int i = 0; i < n; ++i) {
        scanf("%s%d%d", c, &a, &b);
        ad[c[0] - 'a'] = a;
        del[c[0] - 'a'] = b;
    }

    for (int i = m - 1; i >= 0; --i) {
        for (int j = i + 1; j < m; ++j) {
            if (s[i] == s[j]) dp[i][j] = dp[i + 1][j - 1];
            else {
                dp[i][j] = min(dp[i + 1][j] + min(ad[s[i]], del[s[i]]),
                               dp[i][j - 1] + min(ad[s[j]], del[s[j]]));
            }
        }
    }
    printf("%lld\n", dp[0][m - 1]);
    return 0;
}


你可能感兴趣的:(dp)