POJ3280(DP)
题目大意是说一个字符串,每插入或者删除一个字符都需要一定的代价,问怎样可以使这个字符串变成一个回文串,且花费最小。
首先明确的就是如果已经将区间[i,j]整理成为一个回文串(不管中间有多少个字符或者是以什么字符开头或者结尾),当DP到区间[i,j+1]时,我们可以在i-1的位置添加一个str[j+1]字符,或者将在j+1处的字符删除,得到一个新的回文串,而且我们这两步操作都没有借助或者影响区间[i,j]的情况。
因此,那我们就可以将添加或者删除整合在一起,对字符str[j+1]的操作就按照添加和删除中花费最小的一个计算。写出状态转移方程:
DP[j][i] = MIN(DP[j+1][i]+cost[str[j]-'a'], DP[j][i-1]+cost[str[i]-'a']);
if(str[i] == str[j])DP[j][i] = MIN(DP[j][i],DP[j+1][i-1]);
这里的j是按照i-1到0枚举的,由于可能str[i] == str[j],因此也可以不操作,再将 不操作 与 添加或删除区间头或尾 比较。
当然,其实最初的想法是扩展出来四个状态,就是首删除,首添加,尾删除,尾添加,由此扩展开来求一个最小值
1 #include <stdio.h> 2 #include <string.h> 3 #define mem(a) memset(a,0,sizeof(a)) 4 #define MIN(a,b) ((a) < (b) ? (a) : (b)) 5 6 int DP[2005][2005],cost[30],N,M; 7 char str[2005]; 8 9 int main() 10 { 11 while(~scanf("%d%d", &M, &N)) 12 { 13 mem(DP); mem(str); mem(cost); 14 scanf("%s%*c",str); 15 char ch; int x, y; 16 for(int i=0;i<M;i++) 17 { 18 scanf("%c %d %d%*c", &ch, &x, &y); 19 cost[ch-'a'] = MIN(x,y); 20 } 21 for(int i=1;i<N;i++) 22 { 23 for(int j=i-1;j>=0;j--) 24 { 25 DP[j][i] = MIN(DP[j+1][i]+cost[str[j]-'a'], DP[j][i-1]+cost[str[i]-'a']); 26 if(str[i] == str[j])DP[j][i] = MIN(DP[j][i],DP[j+1][i-1]); 27 } 28 } 29 printf("%d\n", DP[0][N-1]); 30 } 31 return 0; 32 }