题意分析:
有一个长度为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; }