详解[USACO07OPEN] Cheapest Palindrome G(洛谷PP2890)(区间DP经典题)

题目

思路

考虑区间DP。

dp[i][j]为从i到j这段区间被修正为回文串的最小花费

   c[cc][1]为添加字符cc的花费

   c[cc][2]为删去字符cc的花费

   s为题目给出的字符串。

  • 用[i + 1,j]区间转移:这种转移相当于在[i+1,j]区间的左边加入一个字符,让[i,j]变为回文的方法为在左边删去该字符或在右边加上该字符,有转移方程:
    dp[i][j] = min(dp[i][j],dp[i + 1][j] + min(c[int(s[i])][1],c[int(s[i])][2]));
  • 用[i,j − 1][i,j − 1]区间转移:这种转移相当于在[i,j−1][区间的右边加入一个字符,方法同上:
dp[i][j] = min(dp[i][j],dp[i][j - 1] + min(c[int(s[j])][1],c[int(s[j])][2]));
  • 当前区间[i,j]满足s[i] == s[j],直接用[i + 1,j − 1]转移:
if(j - i == 1) dp[i][j] = 0;
else dp[i][j] = min(dp[i][j],dp[i + 1][j - 1]);

代码

#include<bits/stdc++.h>
using namespace std;
int n,m,dp[2101][2101],c[255][3],x,y;
//从i到j这段区间被修正为回文串的最小花费
char s[2101],cc;
int main()
{
  cin>>n>>m;
  cin>>s + 1;
  for(int i = 1;i <= n;i++)
  {
    cin>>cc>>x>>y;
    c[int(cc)][1] = x;
    c[int(cc)][2] = y;
  }
  memset(dp,0x3f,sizeof(dp));
  for(int i = 1;i <= m;i++) dp[i][i] = 0;
  for(int l = 1;l <= m;l++)
    for(int i = 1;l + i - 1 <= m;i++)
    {
      int j = i + l - 1;
      dp[i][j] = min(dp[i][j],dp[i + 1][j] + min(c[int(s[i])][1],c[int(s[i])][2]));
      dp[i][j] = min(dp[i][j],dp[i][j - 1] + min(c[int(s[j])][1],c[int(s[j])][2]));
      if(s[i] == s[j])
      {
		if(j - i == 1) dp[i][j] = 0;
		else dp[i][j] = min(dp[i][j],dp[i + 1][j - 1]);
	  }
    }
  cout<<dp[1][m];
  return 0;
}

怎么样?听懂了吗?如果听懂了就请点赞收藏加关注支持一下吧!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值