小码妹有一个长度为 n 的字符串 s 和一个大小为 m 的字符集 现在小码妹希望通过对字符串 s 增加或删去字符,使得 s 变为一个回文串 但是增加或删去不同字符需要花费的代价不同 小码妹希望花费最少的代价达成目标,于是她想寻求你的帮助 输入格式:第一行两个正整数 m和n,分别表示字符集大小和s的长度; 第二行为字符串 s; 接下来 m 行,每行由一个字符 c(数据保证字符c唯一)和两个整数 x,y 组成,之间用空格隔开,表示在 s字符串增加字符 c 需要 x的代价,删去字符 c 需要y 的代价。 输出格式:输出一个整数,表示将 s变为回文串需要的最小代价。 样例 输入:3 4 abcba a 1009 1100 b 350 700 c200 800 输出:900 测试数据保证 1<=m<=26,1<=n <= 2000,1<=x,y <= 10000 且字符集为小写英文字母的子集。写出c语言完整程序
时间: 2024-04-09 07:28:58 浏览: 20
```c
#include <stdio.h>
#include <string.h>
#define MAX 2000
#define MAX_COST 10000
int min(int a int b) {
return a < b ? a : b;
}
int getCost(char s[], int m, int n, c[], int x[], int y[]) {
int dp[MAX_SIZE][MAX_SIZE memset(dp, 0, sizeof(dp));
for (int len = 2; len <= n; len++) {
for (int i = 0; i <= n - len; i++) {
int j = i + len - 1;
if (s[i] == s[j]) {
dp[i][j] = dp[i + 1][j - 1];
} else {
int addCost = x[s[i] - 'a'] + dp[i + 1][j];
int removeCost = y[s[j] - 'a'] + dp[i][j - 1];
dp[i][j] = min(addCost, removeCost);
}
}
}
return dp[0][n - 1];
}
int main() {
int m, n;
scanf("%dd", &m, &n);
char s[MAX_SIZE];
scanf("%s", s);
char c[MAX_SIZE];
int x[MAX_SIZE], y[MAX_SIZE];
for (int i = 0; i < m; i++) {
scanf(" %c %d %d", &c[i], &x[i], &y[i]);
}
int minCost = getMinCost(s, m, n, c, x, y);
printf("%d\n", minCost);
return 0;
}
```
这段代码使用了动态规划的思想。定义一个二维数组dp[i][j]表示将s的子串s[i...j]变为回文串所需要的最小代价。初始时,所有dp[i][i]都为0,表示单个字符本身就是回文串。
然后,通过遍历子串的长度和起始位置来计算dp[i][j]。如果s[i]和s[j]相等,则dp[i][j]等于dp[i+1][j-1],因为只需要将两边的子串变为回文串即可。
如果s[i]和s[j]不相等,则需要选择增加或删除字符来使其相等。假设c是s[i]或s[j]中的一个字符,那么增加字符c的代价是x[c-'a'],删除字符c的代价是y[c-'a']。因此,dp[i][j]等于x[s[i]-'a'] + dp[i+1][j]和y[s[j]-'a'] + dp[i][j-1]中的较小值。
最后,返回dp[0][n-1],即整个字符串s变为回文串所需要的最小代价。
注意:在C语言中,字符串是以'\0'结尾的字符数组,因此可以直接使用scanf函数读取字符串。另外,数组的下标是从0开始的,所以需要将字符映射到0到25的范围内进行处理。