[POJ 3280]Cheapest Palindrome[DP]

来源:互联网 发布:淘宝店如何打快递单 编辑:程序博客网 时间:2024/06/16 15:36
题目链接:[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 longusing 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;}


0 0
原创粉丝点击