小M的回文串

小M的回文串

Description

小M喜欢回文串,回文串就是从左往右和从右往左读都一样的字符串。

现在小X找到小M给了他一个字符串S,希望小M将它变成回文串。

小M可以进行如下三类操作:

  1. add 在字符串的任意位置添加一个字符
  2. erase 删除一个字符
  3. change one letter to another 将某个字符变成另一个

然而,每种操作只能对规定的字符有效。如,小M只能允许erase 'a', add 'b', change 'c' to 'd',且没有其他操作可以使用。 世界上没有免费的午餐,小M的每次操作都有一定的花费。

Input Format

第一行一个字符串,表示小M需要修改的字符串 ( length50 )

第二行一个数N, 表示小M可以使用的操作 ( N50  )

接下来N行,每行一个可以使用的操作,有下面三种形式:

"add c x" : 表示将一个字符c加入到串中需要的花费为x

"erase c x" : 表示将一个字符c从串中删除需要的花费为x

"change c1 c2 x" : 表示将某个字符c1变为c2需要的花费为x

注意,"change c1 c2 x" 不允许将c2变成c1

满足  x100000,c1<>c2  , 且任两行操作不同

Output Format

一行一个数,表示小M将初始的字符串转为回文串的最小花费,如果不可能,输出-1

Sample Input

caaaaaab
6
change b a 100000
change c a 100000
change c d 50000
change b e 50000
erase d 50000
erase e 49999

Sample Output

199999

题解:有几组数据过不了。不知为什么···。先贴上代码,以后再想。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

char s[100];
int ch[40][40], er[40], add[40];
int dp[100][100];
const int INF = 999999999;

void init()
{
    for(int i = 0; i < 26; i++)
    {
        er[i] = add[i] = INF;
        for(int j = 0; j < 26; j++)
            ch[i][j] = (i == j ? 0 : INF);
    }
}

void Floyd()
{
    int i, j, k;
    for(k = 0; k < 26; k++)
        for(i = 0; i < 26; i++)
           for(j = 0; j < 26; j++)
               ch[i][j] = min(ch[i][j], ch[i][k] + ch[k][j]);

    for(i = 0; i < 26; i++)
        for(j = 0; j < 26; j++)
            if(ch[i][j] != INF)
            {
                er[i] = min(er[i], ch[i][j] + er[j]);
                add[i] = min(add[i], ch[i][j] + add[j]);
            }
}

int operDp()
{
    int i, j;
    int len = strlen(s);
    memset(dp,0,sizeof(dp));
    for(i = 0; i < len; i++)
        for(j = i + 1; j < len; j++)
            dp[i][j] = INF;

    for(i = len - 2; i >= 0; i--)
    {
        for(j = i + 1; j < len; j++)
        {
            if(s[i] != s[j])
            {
                if(er[s[i]-'a'] != INF) //在左端删掉s[i]
                    dp[i][j] = min(dp[i+1][j] + er[s[i]-'a'], dp[i][j]);

                if(add[s[i]-'a'] != INF) //在右端加上s[i]
                    dp[i][j] = min(dp[i+1][j] + add[s[i]-'a'], dp[i][j]);

                if(er[s[j]-'a'] != INF) //在右端删掉s[j]
                    dp[i][j] = min(dp[i][j-1] + er[s[j]-'a'], dp[i][j]);

                if(add[s[j]-'a'] != INF) //在左端加上s[j]
                    dp[i][j] = min(dp[i][j-1] + add[s[j]-'a'], dp[i][j]);

                if(ch[s[i]-'a'][s[j]-'a'] != INF)
                    dp[i][j] = min(dp[i+1][j-1] + ch[s[i]-'a'][s[j]-'a'], dp[i][j]); //将左端改成与右端一样
                if(ch[s[j]-'a'][s[i]-'a'] != INF)
                    dp[i][j] = min(dp[i+1][j-1] + ch[s[j]-'a'][s[i]-'a'], dp[i][j]); //将右端改成与左端一样
            }
            else
            {
                if(er[s[i]-'a'] != INF) //在左端删掉s[i]
                    dp[i][j] = min(dp[i+1][j] + er[s[i]-'a'], dp[i][j]);

                if(er[s[i]-'a'] != INF) //在右端加上s[i]
                    dp[i][j] = min(dp[i+1][j] + add[s[i]-'a'], dp[i][j]);

                if(er[s[j]-'a'] != INF) //在右端删掉s[j]
                    dp[i][j] = min(dp[i][j-1] + er[s[j]-'a'], dp[i][j]);

                if(er[s[j]-'a'] != INF) //在左端加上s[j]
                    dp[i][j] = min(dp[i][j-1] + add[s[j]-'a'], dp[i][j]);

                dp[i][j] = min(dp[i+1][j-1], dp[i][j]);
            }
        }
    }
    if(dp[0][len-1] == INF) return -1;
    return dp[0][len-1];
}

int main()
{
    int n, v;
    char c1[3], c2[3], oper[100];
    while(scanf("%s",s) != EOF)
    {
        init();
        scanf("%d",&n);
        while(n--)
        {
            scanf("%s",oper);
            if(strcmp(oper,"change") == 0)
            {
                scanf("%s%s%d",c1, c2, &v);
                ch[c1[0]-'a'][c2[0]-'a'] = v;
            }
            else if(strcmp(oper,"erase") == 0)
            {
                scanf("%s%d",c1,&v);
                er[c1[0]-'a'] = v;
            }
            else
            {
                scanf("%s%d",c1,&v);
                add[c1[0]-'a'] = v;
            }
        }
        Floyd();
        printf("%d\n",operDp());
    }
    return 0;
}







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值