[USACO07OPEN]Cheapest Palindrome G
\(\large{题目链接}\)
\(\\\)
\(\Large\textbf{Solution: } \large{考虑区间dp。设f_{i,j}表示\left[ i,j\right] 构成回文的最小价值。\\如果c_i = c_j那么f_{i,j} = \min (f_{i, j}, f_{i+1,j-1})。然后考虑一般情况,要么f_{i,j}从f_{i + 1,j}转移过来,增加或者删去i,反之一样。}\)
\(\\\)
\(\Large\textbf{Summary: } \large{区间dp有几种转移方式。\\1. f_{i,j}由f_{i,k}和f_{k + 1,j}转移过来。这个时候需要外层由小到大枚举区间长度,内层枚举起点,最里层枚举断点,转移即可。\\2.f_{i,j}由f_{i + 1,j}和f_{i,j - 1}转移过来,此时只需枚举区间长度与起点即可。}\)
\(\\\)
\(\Large\textbf{Code: }\)
#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
int n, m, a[N], b[N], f[N][N];
char c[N], x[N];
int main() {
scanf("%d%d%s", &n, &m, c + 1);
int u, v;
for (int i = 1; i <= n; ++i) scanf("%s%d%d", x, &u, &v), a[x[0] - 'a'] = u, b[x[0] - 'a'] = v;
memset(f, 0x3f, sizeof (f));
for (int i = 0; i <= m; ++i) f[i][i] = 0;
for (int i = 0; i <= m; ++i) for (int j = 0; j < i; ++j) f[i][j] = 0;
for (int k = 1; k <= m; ++k) {
for (int i = 1; (i + k) <= m; ++i) {
int j = i + k;
if (c[i] == c[j]) f[i][j] = min(f[i][j], f[i + 1][j - 1]);
f[i][j] = min(f[i][j], f[i + 1][j] + min(a[c[i] - 'a'], b[c[i] - 'a']));
f[i][j] = min(f[i][j], f[i][j - 1] + min(a[c[j] - 'a'], b[c[j] - 'a']));
}
}
cout << f[1][m] << endl;
return 0;
}