题意
给你长度为N一个字符串,和M个字符,对于每个字符有两种操作:增加或删除,各有一个权值,问将这个串变为一个回文串的最小花费是多少?
思路
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示将
[
i
,
j
]
[i,j]
[i,j]区间变为回文串的最小花费
那么状态转移很容易想到:
①如果
s
[
i
]
=
=
s
[
j
]
s[i]==s[j]
s[i]==s[j],那么
d
p
[
i
]
[
j
]
=
d
p
[
i
+
1
]
[
j
−
1
]
dp[i][j]=dp[i+1][j-1]
dp[i][j]=dp[i+1][j−1]
②如果
s
[
i
]
!
=
s
[
j
]
s[i]!=s[j]
s[i]!=s[j],
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]可以由
d
p
[
i
+
1
]
[
j
]
dp[i+1][j]
dp[i+1][j]和
d
p
[
i
]
[
j
−
1
]
dp[i][j-1]
dp[i][j−1]转移过来。
假定a[i]表示增加i付出的代价,b[i]表示删除i付出的代价,则:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
+
1
]
[
j
]
+
m
i
n
(
a
[
s
[
i
]
−
′
a
′
]
,
b
[
s
[
i
]
−
′
a
′
]
)
)
;
dp[i][j] = min(dp[i][j], dp[i + 1][j] + min(a[s[i] - 'a'], b[s[i] - 'a']));
dp[i][j]=min(dp[i][j],dp[i+1][j]+min(a[s[i]−′a′],b[s[i]−′a′]));
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
+
m
i
n
(
a
[
s
[
j
]
−
′
a
′
]
,
b
[
s
[
j
]
−
′
a
′
]
)
)
;
dp[i][j] = min(dp[i][j], dp[i][j - 1] + min(a[s[j] - 'a'], b[s[j] - 'a']));
dp[i][j]=min(dp[i][j],dp[i][j−1]+min(a[s[j]−′a′],b[s[j]−′a′]));
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
const int MAXN = 2e3 + 5;
const int INF = 0x3f3f3f3f;
int n, m, a[MAXN], b[MAXN], dp[MAXN][MAXN];
char s[MAXN];
int main()
{
memset(a, INF, sizeof(a));
scanf("%d%d%s%*c", &m, &n, s);
while (m--)
{
char c; int x, y; scanf("%c%d%d%*c", &c, &x, &y);
a[c - 'a'] = x, b[c - 'a'] = y;
}
memset(dp, INF, sizeof(dp));
for (int i = 0; i < n; i++) dp[i][i] = 0;
for (int len = 2; len <= n; len++)
{
for (int i = 0; i + len - 1 < n; i++)
{
int j = i + len - 1;
if (s[i] == s[j]) dp[i][j] = (len == 2 ? 0 : dp[i + 1][j - 1]);
dp[i][j] = min(dp[i][j], dp[i + 1][j] + min(a[s[i] - 'a'], b[s[i] - 'a']));
dp[i][j] = min(dp[i][j], dp[i][j - 1] + min(a[s[j] - 'a'], b[s[j] - 'a']));
}
}
printf("%d\n", dp[0][n - 1]);
return 0;
}
/*
3 4
abcb
a 1000 1100
b 350 700
c 200 800
*/