问题1:插入/删除字符使得原字符串变成一个回文串且代价最小

poj 3280 Cheapest Palindrome

题意:给出一个由m中字母组成的长度为n的串,给出m种字母添加和删除花费的代价,求让给出的串变成回文串的代价。

Sol:

  • 插入和删除等价,因此只需要保留 min(插入代价,删除代价)作为调整字符串的代价
  • 如果 s[i]==s[j],那么将区间(i,j)变为回文串的代价和将区间(i+1,j-1)变为回文串的代价相同,因为此时不需要修改
  • 如果不同,必然要将 s[i]和s[j]改为同一字符
  • 第一种情况是,想要将(i,j)变为回文串,可以是在(i+1,j)已是回文串的基础上,在j后面添加字符 s[i],或者直接将i处的字符 s[i] 删掉,取代价小的操作即可
  • 另一种情况是,如果(i,j-1)是回文串,可以将j处的字符删掉或在i前面填加字符s[j],同样取代价小的方式操作

Code:提供几种不同的写法,加深理解

  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[][],cost[],N,M;
  7. char str[];
  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=;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=;i<N;i++)
  22. {
  23. for(int j=i-;j>=;j--)
  24. {
  25. DP[j][i] = MIN(DP[j+][i]+cost[str[j]-'a'], DP[j][i-]+cost[str[i]-'a']);
  26. if(str[i] == str[j])DP[j][i] = MIN(DP[j][i],DP[j+][i-]);
  27. }
  28. }
  29. printf("%d\n", DP[][N-]);
  30. }
  31. return ;
  32. }

1

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. typedef pair<int, int> P;
  5. #define ad first
  6. #define de second
  7. int n, m, dp[][];
  8. char s[];
  9. P ch[]; //ch[ch-'a'].ad代表add一个ch的代价,ch[ch-'a'].de代表delete一个ch的代价
  10. int main()
  11. {
  12. cin >> n >> m >> s;
  13. for (int i = ; i <= n; i++)
  14. {
  15. char Ch;
  16. cin >> Ch;
  17. cin >> ch[Ch - 'a'].ad >> ch[Ch - 'a'].de;
  18. }
  19. for (int i = ; i <= m; i++)
  20. dp[i][i] = ;
  21. for (int i = ; i < m; i++) //注意for循环要实现从短串到长串的过渡,这里i代表长度为i+1
  22. for (int j = ; j + i < m; j++)
  23. if (s[j] == s[j + i]) dp[j][j + i] = dp[j + ][j + i - ];
  24. else
  25. {
  26. int aa = dp[j + ][j + i] + min(ch[s[j] - 'a'].ad, ch[s[j] - 'a'].de);
  27. int bb = dp[j][j + i - ] + min(ch[s[j + i] - 'a'].ad, ch[s[j + i] - 'a'].de);
  28. dp[j][j + i] = min(aa, bb);
  29. }
  30. printf("%d\n", dp[][m - ]);
  31. return ;
  32. }

2

  1. #include <cstdio>
  2. #include <string>
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <cstring>
  6. using namespace std;
  7. const int N = ;
  8. const int M = ;
  9. int add[N];
  10. int dp[M][M];
  11.  
  12. int main()
  13. {
  14. int n,m;
  15. string s;
  16. while(~scanf("%d%d",&n,&m))
  17. {
  18. cin>>s;
  19. char c;int x,y;
  20. for(int i=;i<n;i++)
  21. {
  22. cin>>c>>x>>y;
  23. add[c]=min(x,y);
  24. }
  25. memset(dp,,sizeof(dp));
  26. for(int k=;k<s.size();k++)
  27. {
  28. for(int i=,j=k;j<s.size();i++,j++)
  29. {
  30. dp[i][j]=0x3f3f3f3f;
  31. if(s[i]==s[j])
  32. dp[i][j]=dp[i+][j-];
  33. else
  34. {
  35. dp[i][j]=min(dp[i+][j] + add[s[i]],dp[i][j]);
  36. dp[i][j]=min(dp[i][j-] + add[s[j]],dp[i][j]);
  37. }
  38. }
  39. }
  40. printf("%d\n",dp[][s.size()-]);
  41. }
  42. return ;
  43. }

3


问题2:插入最少多少个字符使得原字符串变成一个回文串

poj 1159 Palindrome

Sol:

首先第一种方法是:

这道题相当于是上一个题中的修改代价为1的情况

因此列出方程:

从上面的分析可以看出,这个问题的实质是求最长公共子序列,只是这两个序列分别是串S的前一部分和串S后一部分的逆序列。

由此引出第二种方法

第二种方法:

先说结论:设原序列S的逆序列为S',最少需要补充的字母数 = 原序列S的长度-S和S'的最长公共子串长度

最后这道题需要对内存进行优化

Code:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4.  
  5. using namespace std;
  6.  
  7. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  8.  
  9. #define MAXSIZE 5005
  10.  
  11. //开始没有考虑内存问题,使用了int型,超内存限制,也可使用滚动数组解决
  12. unsigned short d[MAXSIZE][MAXSIZE];
  13.  
  14. int ToPalindrome(char *s, int n)
  15. {
  16. int i, j, k;
  17. //只有一个字符时,不需要添加字符
  18. for (i = ; i < n; i++)
  19. {
  20. d[i][i] = ;
  21. }
  22. //串长度为2时
  23. for (i = ; i < n; i++)
  24. {
  25. if (s[i-] == s[i])
  26. {
  27. d[i-][i] = ;
  28. }
  29. else
  30. {
  31. d[i-][i] = ;
  32. }
  33. }
  34.  
  35. //串长度递增
  36. for (k = ; k < n; k++)
  37. {
  38. for (i = , j = k; j < n; i++, j++)
  39. {
  40. if (s[i] == s[j])
  41. {
  42. d[i][j] = d[i+][j-];
  43. }
  44. else
  45. {
  46. d[i][j] = MIN(d[i][j-], d[i+][j]) + ;
  47. }
  48. }
  49. }
  50. return d[][n-];
  51. }
  52.  
  53. int main(void)
  54. {
  55. char str[MAXSIZE];
  56.  
  57. int n;
  58. while (scanf("%d", &n) != EOF)
  59. {
  60. getchar();
  61. gets(str);
  62. printf("%d\n", ToPalindrome(str, n));
  63. }
  64. return ;
  65. }

1

  1. #include<cstring>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<iostream>
  5. using namespace std;
  6.  
  7. const int N=;
  8. int n;
  9. char a[N],b[N];
  10. int f[][N];
  11.  
  12. int main(){
  13. while(scanf("%d",&n)!=EOF){
  14. scanf("%s",a+);
  15. for(int i=;i<=n;++i)
  16. b[i]=a[n-i+];
  17. memset(f,,sizeof(f));
  18. for(int i=;i<=n;++i)
  19. for(int j=;j<=n;++j)
  20. if(a[i]==b[j]) f[i%][j]=f[(i-)%][j-]+;
  21. else f[i%][j]=max(f[(i-)%][j],f[i%][j-]);
  22. printf("%d\n",n-f[n%][n]);
  23. }
  24. return ;
  25. }

2

关于回文串的DP问题的更多相关文章

  1. 【GDOI2016模拟3.15】基因合成(回文串+性质+DP)

    [GDOI2016模拟3.15]基因合成 题意: 给一个目标串,要求从空串进行最少的操作次数变成目标串,操作有两种: 在串的头或尾加入一个字符. 把串复制一遍后反向接到串的末尾. 因为有回文操作,所以 ...

  2. 回文串 --- 动态dp UVA 11584

    题目链接: https://cn.vjudge.net/problem/34398/origin 本题的大意其实很简单,就是找回文串,大致的思路如下: 1. 确定一个回文串,这里用到了自定义的chec ...

  3. poj3280 Cheapest Palindrome(回文串区间dp)

    https://vjudge.net/problem/POJ-3280 猛刷简单dp第一天第三题. 这个据说是[求字符串通过增减操作变成回文串的最小改动次数]的变体. 首先增减操作的实质是一样的,所以 ...

  4. 1154 回文串划分(DP+Manacher)

    1154 回文串划分 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 有一个字符串S,求S最少可以被划分为多少个回文串. 例如:abbaabaa,有多种划分方式. ...

  5. uva 10453 【回文串区间dp】

    Uva 10453 题意:给定字符串,问最少插入多少个字符使其变成回文串,并任意输出一种结果. 题解:和Uva 10739类似,这里是只能增加.类似定义dp[i][j]表示子串Si...Sj变为回文串 ...

  6. [LeetCode] Palindrome Partitioning 拆分回文串

    Given a string s, partition s such that every substring of the partition is a palindrome. Return all ...

  7. 计蒜之道 初赛 第三场 题解 Manacher o(n)求最长公共回文串 线段树

    腾讯手机地图 腾讯手机地图的定位功能用到了用户手机的多种信号,这当中有的信号的作用范围近.有的信号作用的范围则远一些.有的信号相对于用户在不同的方位强度是不同的,有的则是在不论什么一个方向上信号强度都 ...

  8. NYOJ 1023 还是回文(DP,花最少费用形成回文串)

    /* 题意:给出一串字符(全部是小写字母),添加或删除一个字符,都会产生一定的花费. 那么,将字符串变成回文串的最小花费是多少呢? 思路:如果一个字符串增加一个字符 x可以形成一个回文串,那么从这个字 ...

  9. poj 1159 dp回文串

    题意:添加最少的字符使之成为回文串 #include<cstdio> #include<iostream> #include<algorithm> #include ...

随机推荐

  1. 【转载】java InputStream读取数据问题

    原文链接:http://www.cnblogs.com/MyFavorite/archive/2010/10/19/1855758.html 1. 关于InputStream.read()     在 ...

  2. openjudge8465:马走日 [搜索]

    描述 马在中国象棋以日字形规则移动. 请编写一段程序,给定n*m大小的棋盘,以及马的初始位置(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点. 输入 第一行为整数T ...

  3. (转)Memcached 在windows下的java使用

    Memcached 在windows下的java使用   研究这个东东主要是为了解决在教务管理中选课系统的大并发情况下数据库频繁读写造成速度慢的问题,但要使用WEB服务器的内存,是不是可靠还需要验证, ...

  4. 【JAVASCRIPT】React学习-组件生命周期

    摘要 整理组件加载过程,详细见官方文档:https://facebook.github.io/react/docs/react-component.html mount 过程 1)constructo ...

  5. ThreadLocal源码分析(转)

    阅读总结: ThreadLocal内部使用静态map存储,每个变量对应一个hashcode,不需要指定key值,后台动态生成,good! 每个变量ThreadLocal内部分配Entry,获取值时,通 ...

  6. IntelliJ idea学习资源

    工作需要, 最近得从Eclipse转战到Idea, 找了些不错的学习资料: 1, 从eclipse上迁移过来的用户说明: https://www.jetbrains.com/help/idea/201 ...

  7. kafka使用场景

    kafka使用场景 消息 Kafka被当作传统消息中间件的替代品.消息中间件的使用原因有多种(从数据生产者解耦处理,缓存未处理的消息等).与大多数消息系统相比,Kafka具有更好的吞吐量,内置的分区, ...

  8. 如何编写轻量级 CSS 框架

    Github 地址: https://github.com/nzbin/snack Demo 演示: https://nzbin.github.io/snack/ 前言 这篇文章我已经酝酿了半年之久, ...

  9. vue指令v-pre示例解析

    v-pre会跳过该元素及其子元素的编译过程,显示原始标签. <div id="app"> <span v-pre>{{msg}} 这句不会编译</sp ...

  10. [STL] day 1~2 Problem Set

    Q#1 #include <cmath> #include <cstdio> #include <vector> #include <iostream> ...