动态规划入门19.docVIP

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
  4. 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
  5. 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们
  6. 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
  7. 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
动态规划入门19

动态规划入门19 动态规划入门19 分类:算法与数据结构 例题18 回文词 (palin.pas/c/cpp) 来源:IOI 2000 【问题描述】 回文词是一种对称的字符串——也就是说,一个回文词,从左到右读和从右到左读得到的结果是一样的。任意给定一个字符串,通过插入若干字符,都可以变成一个回文词。你的任务是写一个程序,求出将给定字符串变成回文词所需插入的最少字符数。   比如字符串“Ab3bd”,在插入两个字符后可以变成一个回文词(“dAb3bAd”或“Adb3bdA”)。然而,插入两个以下的字符无法使它变成一个回文词。 【输入文件】 第一行包含一个整数N,表示给定字符串的长度,3=N=5000  第二行是一个长度为N的字符串,字符串由大小写字母和数字构成。 【输出文件】 一个整数,表示需要插入的最少字符数。 【输入样例】 5 Ab3bd 【输出样例】 2 【问题分析】 所谓回文词(正着读和反着读一样),其实就是从中间断开把后面翻转后与前面部分一样(注意奇数和偶数有区别)。例: 回文词:AB3BA 断开:AB BA (奇数个时去掉中间字符) 翻转:AB AB 这个题目要求出最少填几个数可以使一个字符串变成回文词,也就是说从任意点截断,再翻转后面部分后。两个序列有相同的部分不用添字符,不一样的部分添上字符就可以了。例: 回文词:Ab3bd 截断:Ab bd 翻转:Ab db b在两个序列里都有,在第二个里添A在第一个里添d就可以了: Adb Adb 这样添两个就可以了, 显然从别的地方截断添的个数要比这样多。 这样就把原问题抽象成求最长公共子序列问题了。枚举截断点,把原串截断,翻转。求最长公共子序列。答案就是len-(ans*2) len是翻转后两个序列的长度和。Ans 是最长公共子序列的长度。 其实这样求解很麻烦,做了好多重复的工作。仔细想想既然在最后求解ans还要乘2那么在先前计算时直接把原串翻转作为第二个序列和第一个序列求最长公共子序列就可以了。这样最后求解就不用乘2了,也不用枚举截断点了例: 原串:Ab3bd 翻转:db3bA 最长公共子序列b3b 添加2个字符 怎么理解这个优化呢? 其实翻转了序列后字符的先后顺序就变了,求解最长公共子序列中得到的解,是唯一的,也就是说这个序列的顺序是唯一的,如果在翻转后的序列和原串能得到相同的序列,那么这个序列在两个串中字符间的顺序是横定的,着就满足了回文词的定义(正着读和反着读一样)。所以这个优化是正确的。 注意: 这个问题的数据规模很大,空间复杂度交高(O(N2))所以要用到滚动数组,如果不知道什么是滚动数组就该往后翻页,应为我在后面的动态规划的优化里会说到。 【源代码1】 program P1327; const maxn=5002; var a,b:ansistring; opt:array[0..1,0..maxn] of longint; n,ans:longint; function max(x,y:longint):longint; begin if xy then exit(x); max:=y; end; procedure main; var i,x,j,k0,k1:longint; begin fillchar(opt,sizeof(opt),0); readln(n); readln(a); b:=; for i:=n downto 1 do b:=b+a[i]; k0:=0; k1:=1; for i:=1 to n do begin fillchar(opt[k1],sizeof(opt[k1]),0); for j:=1 to n do begin opt[k1,j]:=max(opt[k0,j],opt[k1,j-1]); if a[i]=b[j] then opt[k1,j]:=max(opt[k1,j],opt[k0,j-1]+1); end; x:=k0; k0:=k1; k1:=x; end; writeln(n-opt[k0,n]); end; begin main; end. 用这个方法AC了就该很高兴了,但不要停止思考的步伐,还有别的方法么? 从原问题出发,找这个问题的子问题。和上面说的最长公共子序列问题一样,设计序列的问题我们一般要考虑它的子序列,也就是更短的序列。 这样就回到了我第一节说的边界条件法了。 显然单独的

文档评论(0)

sy78219 + 关注
实名认证
文档贡献者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档