题目意思:给一个字符串和每个字母删除、插入的代价,求把它变成回文串的最小代价
dp[i][j] 表示 区间 i~j 的子串变成回文串需要的最小代价。
设字符串 ab....cd
如果 a == d,则将其变成回文串的最小代价就是将 b....c 变成回文串
如果 a != d,考虑如下四种情况
在左边插入一个等于 d 的字符变成 dab....cd,则将其变成回文串的代价是将 ab....c 变成回文串的代价,加上插入 d 的代价。
在将左边的 a 删除变成 b....cd,则将其变成回文串的代价是将 b....cd 变成回文串的代价,再加上删除 a 的代价。
右边的情况一样。
取上面四种情况代价最小的
代码:
#include <iostream> #include <cstring> using namespace std; const int MAX = 2005; int dp[MAX][MAX]; //i....j 变成回文的最小代价 int v1[130]; //增加代价 int v2[130]; //删除代价 char s[MAX]; int n, m; int main(){ // freopen("input.txt", "r", stdin); cin >> n >> m; cin >> s+1; // getchar(); for(int i=1; i<=n; i++){ char ch; cin >> ch; cin >> v1[(int)ch] >> v2[(int)ch]; } //DP memset(dp, 0, sizeof(dp)); for(int len=1; len<=m; len++){ for(int i=1; i+len-1<=m; i++){ int j = i + len - 1; if(s[i] == s[j]) //如果两端点相等 dp[i][j] = dp[i+1][j-1]; //等于把两头去掉后中间的串变成回文的代价。(如果 i == j 或 i+1 == j ,此时 dp[i+1][j-1] = 0 else{ int left = min(dp[i+1][j] + v2[s[i]], dp[i][j-1] + v1[s[j]]); //如果增加或删除左边的 int right = min(dp[i][j-1] + v2[s[j]], dp[i+1][j] + v1[s[i]]); //如果增加或删除右边的 dp[i][j] = min(left, right); } // cout << i << " " << j << " " << dp[i][j] << endl; } } cout << dp[1][m]; return 0; }