POJ3280

  • Post author:
  • Post category:其他




题意:

对一个字符串进行插入删除等操作使其变成一个回文串,但是对于每个字符的操作消耗是不同的。求最小消耗。



思路:

我们定义dp [ i ] [ j ] 为区间 i 到 j 变成回文的最小代价。

那么对于dp【i】【j】有三种情况

首先:对于一个串如果s【i】==s【j】,那么dp【i】【j】=dp【i+1】【j-1】

其次:如果dp【i+1】【j】是回文串,那么dp【i】【j】=dp【i+1】【j】+min(add【i】,del【i】);

最后,如果dp【i】【j-1】是回文串,那么dp【i】【j】=dp【i】【j-1】 + min(add【j】,del【j】);

显然是一个dp问题,可以设定状态dp[i][j]表示从i~j这一段变成回文的最小消耗,显然状态转移就是

if(s[i]==s[j])

dp[i][j]=dp[i+1][j-1];

else

dp[i][j]=min(dp[i+1][j]+w[s[i]-‘a’],dp[i][j-1]+w[s[j]-‘a’]);

首先明确的就是如果已经将区间[i,j]整理成为一个回文串(不管中间有多少个字符或者是以什么字符开头或者结尾),当DP到区间[i,j+1]时,我们可以在i-1的位置添加一个str[j+1]字符,或者将在j+1处的字符删除,得到一个新的回文串,而且我们这两步操作都没有借助或者影响区间[i,j]的情况。

因此虽然删除和插入不同,但是这两种操作是等价的,这头加和那头减是一样的,那我们就可以将添加或者删除整合在一起,对字符str[j+1]的操作就按照添加和删除中花费最小的一个计算

另一个注意点是两重循环的方向,起点i应当趋0,终点j应当趋M

代码:

#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int f[2005][2005];
int main()
{
    string str;int n,m,i,j,cost[30];
    cin>>n>>m;getchar();getline(cin,str);
    for(i=1;i<=n;i++){
        char c;int cost1,cost2;cin>>c>>cost1>>cost2;
        cost[c-'a']=min(cost1,cost2);
    }
    for(i=str.size()-2;i>=0;i--){
        for(j=i+1;j<str.size();j++){
            if(str[i]==str[j])f[i][j]=f[i+1][j-1];
            else{
                f[i][j]=min(f[i+1][j]+cost[str[i]-'a'],f[i][j-1]+cost[str[j]-'a']);
            }
        }
    }
    cout<<f[0][str.size()-1]<<endl;

    return 0;
}

在这里插入图片描述



版权声明:本文为weixin_48347480原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。