Cheapest Palindrome POJ - 3280【dp-区间dp 回文】
分析
定义状态:dp[i][j] 为把区间i~j变成回文的最小代价
转移:
s[i]==s[j] dp[i][j]=dp[i+1][j-1]
如果 s[i+1]~s[j]是回文串 则对于s[i]可以增加可以删除,dp[i][j]=dp[i+1][j]+min(ac(s[i]),dc(s[i]))
如果 s[i]~s[j-1]是回文串 则对于s[j]可以增加可以删除,dp[i][j]=dp[i][j-1]+min(ac(s[j]),dc(s[j]))
(有同志问为什么dp[i+1][j]可以对应条件 如果 s[i+1]~s[j]是回文串 其实就是对于dp[i+1][j],既然它都表示变成回文的代价了,那这个区间就是回文,如果它已经计算过,就可以直接转移 这是dp呐 不是说要判断它是否回文,利用这样的思路计算代价而已 如果你没有这样的疑问,请略过此处)
这几种情况取min
由于dp[i][j]要从dp[i+1][j-1]、dp[i+1][j]、dp[i][j-1]中转移过来,所以i反着枚举,j正着枚举
几种情况取min dp[i][i]要置为0(一个字符本身就是回文)
考虑到对于一个字符增加和删除对结果并没有什么影响,所以只要对这个字符有改动就用增加的删除中的小的代价
那么在存储时可以只存ac和dc中小的那一个
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXM 2010
#define INF 0x3f
int n,m;
char s[MAXM];
int c[26];
int dp[MAXM][MAXM];//区间i~j的最小代价
int main()
{
scanf("%d %d",&n,&m);
scanf("%s",s);//从0开始!!!
for(int i=1;i<=n;i++)
{
char tmp[5];//有换行符,非常非常非常非常非常坑!!!
int x,y;
scanf("%s",tmp);
scanf("%d %d",&x,&y);
c[tmp[0]-'a']=min(x,y);
}
for(int i=m-1;i>=0;i--)
{
dp[i][i]=0;
for(int j=i+1;j<m;j++)
{
dp[i][j]=INF;//之前用memset和fill全局清都WA了,至今未果,还是不要随便全局了,只清要比较的qwq
if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1];
dp[i][j]=min(dp[i][j],dp[i+1][j]+c[s[i]-'a']);
dp[i][j]=min(dp[i][j],dp[i][j-1]+c[s[j]-'a']);
}
}
printf("%d\n",dp[0][m-1]);
return 0;
}
转载请注明出处,有疑问欢迎探讨
博主邮箱 2775182058@qq.com