题目大意:
给一个字符串
可以再任意位置添加或删除字母(给出花费的) 使得字符串变成回文
做法:
其实添加和删除的性质是一样的
添加一个字母和删去相对应的字母 对于使原文变成回文
的贡献是一样的 所以我们取花费的时候 只取小的花费
为了理解方面统一用删除吧
从两端进行遍历
1 如果对应相等 则直接去掉就可以 (无需花费)
2 如果只有一个字符了 直接去掉 (无需花费)
3 否则选择删掉左边 和 删掉右边 两种情况中最优的(只有给出花费才能删)出花费的) 使得字符串变成回文
注意:
用一个数组标记,目的是为了记忆这个状态曾经的结果。
代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<stdlib.h>
#define INF_MAX 0x7fffffff
#define INF 999999
#define max3(a,b,c) (max(a,b)>c?max(a,b):c)
#define min3(a,b,c) (min(a,b)<c?min(a,b):c)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
struct node
{
int u;
int v;
int w;
bool friend operator < (node a, node b){
return a.w < b.w;
}
}edge[1001];
int gcd(int n,int m){if(n<m) swap(n,m);return n%m==0?m:gcd(m,n%m);}
int lcm(int n,int m){if(n<m) swap(n,m);return n/gcd(n,m)*m;}
int v[27];
char str[10001];
int as[2001][2001];
int dos(int l,int r)
{
if(l>r)return 0;
if(as[l][r]!=-1)return as[l][r];//记忆化搜索
if(l==r)
{
as[l][r]=0;
return 0;
}
else if(str[l]==str[r])
{
as[l][r]=dos(l+1,r-1);
return as[l][r];
}
else
{
as[l][r]=min(dos(l+1,r)+v[str[l]-'a'],dos(l,r-1)+v[str[r]-'a']);
return as[l][r];
}
}
int main()
{
int n,m,i,a,b;
char c;
scanf("%d%d%*c",&n,&m);
gets(str);
mem(as,-1);
for(i=0;i<n;i++)
{
scanf("%c%d%d%*c",&c,&a,&b);
v[c-'a']=min(a,b);
}
as[0][m-1]=dos(0,m-1);
printf("%d\n",as[0][m-1]);
return 0;
}