POJ 3280 Cheapest Palindrome(水题)

题意:给定一个完全由小写字母组成的字符串s,对每个字母比如x(或a,b,c...z),在字符串中添加或者删除它分别需要花费c1['x']和c2['x']的代价,问将给定字符串变成回文串所需要的最少代价为多少。

解法:设d[i][j]表示将字符串中从第i位至第j位变成回文串所需要的代价。若s[i] == s[j],d[i][j] = d[i+1][j-1];否则的话,有四种处理方法。

   对xa.......by,可以将其变为xa......b,yxa.....by,a.......by,xa.....byx中的任意一种再处理。所以d[i][j] = min(d[i][j-1] + c2[s[j]], d[i][j-1] + c1[s[j]], d[i+1][j] + c2[s[i]], d[i+1][j] + c1[s[i]])。化简为d[i][j] = min(d[i][j-1] + min(c1[s[j]], c2[s[j]]), d[i+1][j] + min(c1[s[i]], c2[s[i]]))。(此公式看着没有化简,但实际上可以省很多代码,我的代码改了以后少了近200b)

tag:字符串,回文串,dp

 1 /*
 2  * Author:  Plumrain
 3  * Created Time:  2013-11-17 21:44
 4  * File Name: DP-POJ-3280.cpp
 5  */
 6 #include <iostream>
 7 #include <cstdio>
 8 #include <cstring>
 9 #include <map>
10 #include <utility>
11 
12 using namespace std;
13 
14 #define CLR(x) memset(x, 0, sizeof(x))
15 const int maxint = 2147483647;
16 
17 char s[3000];
18 int d[2005][2005];
19 map<char, int > mp;
20 
21 int main()
22 {
23     int n, len;
24     while (scanf ("%d%d", &n, &len) != EOF){
25         scanf ("%s", s);
26         char x;
27         int t1, t2;
28         mp.clear();
29         for (int i = 0; i < n; ++ i){
30             x = 'P';
31             while (!(x >= 'a' && x <= 'z')) scanf ("%c", &x);
32             scanf ("%d%d", &t1, &t2);
33             mp[x] = min(t1, t2);
34         }
35         
36         CLR (d);
37         for (int i = 0; i < len; ++ i)
38             d[i][i] = 0;
39         for (int i = len-2; i >= 0; -- i)
40             for (int j = i+1; j < len; ++ j){
41                 if (s[i] == s[j]) d[i][j] = d[i+1][j-1];
42                 else
43                     d[i][j] = min(maxint, min(d[i+1][j] + mp[s[i]], d[i][j-1] + mp[s[j]]));
44             }
45         printf ("%d\n", d[0][len-1]);
46     }
47     return 0;
48 }
View Code

 

posted @ 2013-11-18 15:32  Plumrain  阅读(210)  评论(0编辑  收藏  举报