这段时间要沉迷刷题一段时间了,就让CSDN陪我一起吧!
一、题目大意
这道题的题意很简单,第一行给出两个整数N和M,N表示组成字符串的字符种类数,M表示字符串的字符个数,然后第二行给出一个字符串,之后N行,每行给出一个字符添加和删除的开销,求解要把整个字符串通过添加或删除字符调整为回文字符串所需的最小开销。
二、题目思路以及AC代码
这题可能在大佬面前就是送分题了,但对我还是需要思考的。
首先我们要明白这是一个DP题,我们定义dp[i][j]的含义为,把字符串从i到j的子串变化为回文串所需的最小代价。这样我们最终的目的其实就是求解dp[0][M-1]。
接下来就是递推公式(我用s表示输入字符串):
-
如果s[i] == s[j]的话,那dp[i][j] = dp[i+1][j-1],因为我新增加s[i]和s[j]并没有多余的开销,所以最小代价还是等于没增加时候的最小代价,也就是dp[i+1][j-1]
-
如果s[i] != s[j]的话,那dp[i][j]就可以通过dp[i+1][j]和dp[i][j-1]来进行转化。举例说明,对于dp[i+1][j],要想转化为dp[i][j]的话,则需要增加s[i],如果只增加s[i]而不做任何动作的话,那么并不是dp[i][j],因为其并不是回文串,所以我们需要删除s[i]或者在s[j]后增加s[i],才可以得到dp[i][j],也就是我们需要取两者的最小值,作为dp[i][j]的新值。同时dp[i][j-1]的转化也是一样,所以得这种条件下最终的转化公式为:
dp[i][j] = min(dp[i + 1][j] + min(in_add[str[i] - ‘a’], in_del[str[i] - ‘a’]),
dp[i][j - 1] + min(in_add[str[j] - ‘a’], in_del[str[j] - ‘a’]));
这道题是一道比较经典的区间dp题,可以好好学习一下!
下面给出AC代码:
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#define MAXM 2010
#define INF 2147483647
using namespace std;
int in_add[26];
int in_del[26];
int N, M;
int dp[MAXM][MAXM];
void init() {
for (int i = 0; i < MAXM; i++) {
for (int j = 0; j < MAXM; j++) {
dp[i][j] = 0;
}
}
for (int i = 0; i < 26; i++) {
in_add[i] = 0;
in_del[i] = 0;
}
}
int main()
{
init();
scanf("%d%d", &N, &M);
string str;
cin >> str;
for (int i = 0; i < N; i++) {
char c;
cin >> c;
cin >> in_add[c - 'a'] >> in_del[c - 'a'];
// scanf("%d%d", &in_add[c - 'a'], &in_del[c - 'a']);
}
for (int i = 0; i <= M; i++) {
dp[i][i] = 0;
}
for (int j = 1; j <= M - 1; j++) {
for (int i = j - 1; i >= 0; i--) {
if (str[i] == str[j])
dp[i][j] = dp[i + 1][j - 1];
else {
dp[i][j] = min(dp[i + 1][j] + min(in_add[str[i] - 'a'], in_del[str[i] - 'a']),
dp[i][j - 1] + min(in_add[str[j] - 'a'], in_del[str[j] - 'a']));
}
}
}
printf("%d\n", dp[0][M - 1]);
return 0;
}
如果有什么问题,欢迎大家指正!!!