// 16520K 141MS G++
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
struct OP {
char valid;
int addCost;
int removeCost;
};
const int MAX = 2010;
long DP[MAX][MAX];
typedef struct OP OP;
OP validChar[26];
int M;
int N;
#define INVALID -1
#define INF 999999999
char str[MAX];
inline long min(long a, long b) {
return a < b ? a: b;
}
void beginDP() {
for (int begin = M; begin >=1; begin--) {
for (int end = begin; end <= M; end++) {
if (begin == end) { // only on char, no need remove or add
DP[begin][end] = 0;
} else if (begin < end) {
// 2 char same, no need remove/add
if (str[begin-1] == str[end-1]) {
if (begin + 1 == end) {
DP[begin][end] = 0;
} else {
DP[begin][end] = DP[begin+1][end-1];
}
} else {
char beginChar = str[begin-1];
char endChar = str[end-1];
int beginCharPos = beginChar - 'a';
int endCharPos = endChar - 'a';
DP[begin][end] = INF;
// case 1: add end before begin
long case1Val = INF;
if (validChar[endCharPos].valid) {
if (DP[begin][end-1] != -1) {
DP[begin][end] = min(DP[begin][end-1]
+ validChar[endCharPos].addCost, DP[begin][end]);
}
}
// case 2: add begin after end
long case2Val = INF;
if (validChar[beginCharPos].valid) {
if (DP[begin+1][end] != -1) {
DP[begin][end] = min(DP[begin+1][end]
+ validChar[beginCharPos].addCost, DP[begin][end]);
}
}
// case 3: remove begin
long case3Val = INF;
if (validChar[beginCharPos].valid) {
if (DP[begin+1][end] != -1) {
DP[begin][end] = min(DP[begin+1][end]
+ validChar[beginCharPos].removeCost, DP[begin][end]);
}
}
// case 4: remove end
long case4Val = INF;
if (validChar[endCharPos].valid) {
if (DP[begin][end-1] != -1) {
DP[begin][end] = min(DP[begin][end-1]
+ validChar[endCharPos].removeCost, DP[begin][end]);
}
}
if (DP[begin][end] == INF) {
DP[begin][end] = -1;
}
}
}
}
}
}
void getMinCost() {
memset(DP, INVALID, sizeof(DP));
beginDP();
printf("%ld\n", DP[1][M]);
}
int main() {
// scanf("%d %d", &N, &M);
while(scanf("%d %d", &N, &M) != EOF) {
memset(validChar, 0, sizeof(validChar));
scanf("%s%*c",str);
// scanf("%s", str);
for (int i = 1; i <= N; i++) {
char Char;
int addCost;
int removeCost;
scanf("%c %d %d%*c", &Char, &addCost, &removeCost);
int pos = Char - 'a';
validChar[pos].valid = 1;
validChar[pos].addCost = addCost;
validChar[pos].removeCost = removeCost;
}
getMinCost();
}
}
唉,一道简单的DP变形题, 基础就是经典的回文串组成,只不过这次加入了一些限制,只能增加或删除某些字母,
我的code写的是最朴素的逻辑,实际上add和remove在某种意义上是一样的,因此不必分开讨论add和remove, 只保留最小者即可,很多这样的code写的极为简洁,不过无所谓了,我的出发点是以清晰为主,哪怕冗余,就像epp写的书一样。
这道题本身没啥可说,不过犯了一个很低级的错误,导致WA了6,7次......
一开始定义INF时, 考虑到DP数组是long的,于是就搞一个一个超int的数,测试数据OK,提交谁知道竟然WA了,又找了原题的测试数组,发现一个逻辑小问题,就是在
if (str[begin-1] == str[end-1]) {
if (begin + 1 == end) {
DP[begin][end] = 0;
} else {
DP[begin][end] = DP[begin+1][end-1];
}
}
这里没有考虑begin + 1 == end的情况,唉低级错误,在这里mark一下,别再犯。
把原题的数据跑了一遍都OK,提交等AC,谁料又是WA..... , 反复改了几次M范围,输入数据格式啥的,都不管用,
后来,突然发现一点,long和int在32位机上其实长度一样,都是4, 我的机器是64位,因此long是8字节,可以放下INF,而POJ的机器应该是32位的,那么INF必然溢出,就悲剧了......,把INF改小了,就OK了,唉 这种问题也要长心了,不然这种题WA个6,7次,tai