给定一些字符集,将字符集中的字符从字符串中删除或增加需要一些代价,问构造一个回文串的最小代价。
因为删除与增加本质是相同的,所以只保存代价最小的然后进行字符的删除。
考虑区间转移,然后存下所有区间的最小状态即可。
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <queue> #include <vector> #include <set> #include <map> using namespace std; //删除和增加一个字符本质是一样的,所以只需要存删除或者增加的最小值即可 int n,m,mx,mn; int dp[2107][2107];//存区间i到j为回文的最小代价 char s[2107]; char c[2]; map<char,int> mp; int dfs(int st,int ed){ if(st>ed) return 0; if(dp[st][ed]!=-1) return dp[st][ed];//如果这个区间状态已经存在直接返回 if(st==ed){//只剩下一个字符代价为0 dp[st][ed]=0; return 0; } if(s[st]==s[ed]){//区间左右字符相等则无代价删除左右两端 dp[st][ed]=dfs(st+1,ed-1); return dp[st][ed]; } int fst=dfs(st+1,ed)+mp[s[st]],fed=dfs(st,ed-1)+mp[s[ed]];//取删除左边或者右边的最小代价 dp[st][ed]=min(fst,fed); return dp[st][ed]; } int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); while(~scanf("%d%d",&n,&m)){ memset(dp,-1,sizeof(dp)); memset(s,0,sizeof(s));mp.clear(); scanf("%s",s); for(int i=1;i<=n;i++){ scanf("%s%d%d",c,&mx,&mn); mn=min(mn,mx); mp[c[0]]=mn; } printf("%d\n",dfs(0,m-1)); } return 0; }