小M的回文串
Description
小M喜欢回文串,回文串就是从左往右和从右往左读都一样的字符串。
现在小X找到小M给了他一个字符串S,希望小M将它变成回文串。
小M可以进行如下三类操作:
- add 在字符串的任意位置添加一个字符
- erase 删除一个字符
- change one letter to another 将某个字符变成另一个
然而,每种操作只能对规定的字符有效。如,小M只能允许erase 'a', add 'b', change 'c' to 'd',且没有其他操作可以使用。 世界上没有免费的午餐,小M的每次操作都有一定的花费。
Input Format
第一行一个字符串,表示小M需要修改的字符串 ( length≤50 )
第二行一个数N, 表示小M可以使用的操作 ( N≤50 )
接下来N行,每行一个可以使用的操作,有下面三种形式:
"add c x" : 表示将一个字符c加入到串中需要的花费为x
"erase c x" : 表示将一个字符c从串中删除需要的花费为x
"change c1 c2 x" : 表示将某个字符c1变为c2需要的花费为x
注意,"change c1 c2 x" 不允许将c2变成c1
满足 x≤100000,c1<>c2 , 且任两行操作不同
Output Format
一行一个数,表示小M将初始的字符串转为回文串的最小花费,如果不可能,输出-1
Sample Input
Sample Output
题解:有几组数据过不了。不知为什么···。先贴上代码,以后再想。
#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;
}