[USACO07OPEN]Cheapest Palindrome G

(large{题目链接})
(\)
(Large extbf{Solution: } large{考虑区间dp。设f_{i,j}表示left[ i,j ight] 构成回文的最小价值。\如果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 extbf{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 extbf{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;
} 
原文地址:https://www.cnblogs.com/Miraclys/p/12686276.html