[luoguP2890] [USACO07OPEN]便宜的回文Cheapest Palindrome(DP)

传送门

f[i][j] 表示区间 i 到 j 变为回文串所需最小费用

1.s[i] == s[j]  f[i][j] = f[i + 1][j - 1]

2.s[i] != s[j]  f[i][j] = min(f[i + 1][j] + cost[s[i]], f[i][j - 1] + cost[s[j]])

开头去掉一个字母和结尾增加一个字母的效果是一样的

所以 cost[s[i]] = min(add[s[i]], del[s[i]])

——代码

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 
 5 int n, m;
 6 int a[301], f[2010][2010];
 7 char s[2010];
 8 
 9 inline int read()
10 {
11     int x = 0, f = 1;
12     char ch = getchar();
13     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
14     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
15     return x * f;
16 }
17 
18 inline int min(int x, int y)
19 {
20     return x < y ? x : y;
21 }
22 
23 inline int dp(int x, int y)
24 {
25     if(x >= y) return f[x][y] = 0;
26     if(f[x][y] ^ -1) return f[x][y];
27     if(s[x] == s[y]) return f[x][y] = dp(x + 1, y - 1);
28     else return f[x][y] = min(dp(x + 1, y) + a[s[x]], dp(x, y - 1) + a[s[y]]);
29 }
30 
31 int main()
32 {
33     int i;
34     char c[1];
35     n = read();
36     m = read();
37     scanf("%s", s + 1);
38     for(i = 1; i <= n; i++)
39     {
40         scanf("%s", c);
41         a[c[0]] = min(read(), read());
42     }
43     memset(f, -1, sizeof(f));
44     printf("%d
", dp(1, m));
45     return 0;
46 }
View Code
原文地址:https://www.cnblogs.com/zhenghaotian/p/6921430.html