﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-C++ Coder-随笔分类-数据结构与算法</title><link>http://www.cppblog.com/jackdongy/category/20070.html</link><description>HCP高性能计算架构，实现，编译器指令优化，算法优化，
  LLVM   CLANG   OpenCL   CUDA   OpenACC    C++AMP   OpenMP   MPI</description><language>zh-cn</language><lastBuildDate>Thu, 10 Jan 2013 12:16:20 GMT</lastBuildDate><pubDate>Thu, 10 Jan 2013 12:16:20 GMT</pubDate><ttl>60</ttl><item><title>深入学习算法的一点拙见 </title><link>http://www.cppblog.com/jackdongy/archive/2013/01/08/197110.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Tue, 08 Jan 2013 06:56:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2013/01/08/197110.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/197110.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2013/01/08/197110.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/197110.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/197110.html</trackback:ping><description><![CDATA[<a href="http://blog.csdn.net/midgard/article/details/4084884">http://blog.csdn.net/midgard/article/details/4084884</a><br /><br />
<div>今天实在是头脑不听使唤了，没力气看书，写代码了。写点总结吧。</div>
<div>都说算法是内功，究竟练到什么程度才算修成了呢？</div>
<div>&nbsp;</div>
<div>为什么要学习，强化算法？</div>
<div>首先强调的是，下面的原因均是建立在算法熟练到一定程度后的效果。不熟的话，未见得能达到效果。这些原因很现实。但很多程序员却不知道或不以为然。</div>
<ol><li>
<div>比较世俗的方面，顶级软件公司笔试，面试会问到。别说你不想去谷歌，百度，微软，如果真的没想过，我希望你能想想自己是否具备进入的实力。如果还是没兴趣想，那就忘了这条，看看下面的原因吧。</div></li><li>
<div>如果算法熟练，能显著提高看代码的速度，越是工作久了，越会发现很多时候是在读别人写的代码，然后在其基础上追加功能，或修改bug。所以这是很现实的技能。</div></li><li>算法操练上手快，注意只是快，但不见得容易。因为练习省去了界面等操作，只利用编译器最基本的功能，非常适合初学者，编程环境不十分熟练的人来学习，别小看这一点，这能让你不论在家，在同学的电脑上，甚至在网吧，只要你想操练都是能迅速找到办法写程序实现的。 </li><li>
<div>难学，有区分度，正因为难，属于内功级别的学习，不是工具型的学习，所以她经久不衰，这项技能能让你不论什么时候都能作为一个亮点技能展示，并运用。比如眼下学python的人不少，但如果再出现更进步，高效的语言，而且这是完全有可能的，又需要重新学习，那什么才是被各种纷繁语言覆盖的，能让你拥有后在短时间能适应任何语言层面的转换工作，更为通用的技能呢？无疑，数据结构+算法是其中一个，而且是非常重要的一项技能。而更为重要的是，算法这种技能，最实实在在的在于他的优势持久性，周围的人如果没有经过大量算法编码训练，只是看过书写过简单算法的人是很难短期内超越你的。也就是说，这项技能越高越能保证你的能力、水平在社会上具有唯一性。即：稀缺人才。</div></li><li>
<div>很多简单的UI操作，短期培训班出来的照着做也能做出来很炫的效果，要佩服微软的封装工作，把UI设计大大简化了。</div></li><li>
<div>对编程语言的基本功能会得到大量强化，比如操作符重载，数组，指针的运用，类的构建，对字符串的操作，以及STL，泛型的理解、运用。这里我想你应该看到了学习算法的过程是如何与计算机应用建立起了联系，因为你肯定在写程序时无数次与这些内容打交道，当然，不深入学习算法，也同样可以获得这些知识，而且.NET,Java,已经封装了非常多的这类基础操作，使得字符串处理变得容易多了。这就要看你的风格，需求了。这里我只是介绍深入学习算法能带来的好处，至于不深入学习有没有坏处，我不做评价。注意"深入"二字的修饰作用，如果没学过基本的数据结构，甚至数组、链表都没搞懂区别的话，那做程序员一定是不行的。迟早会遇到瓶颈，而且很快。</div></li><li>
<div>提供了足够的可扩展空间。对计算机科学的深层研究必备武器，比如操作系统，搜索引擎，编译器等等。要分析linux源代码，会发现，操作系统在内存管理，进程，线程管理，文件管理，协议栈中，运用了大量算法实现，如果基本算法都不理解，甚至不知道，很难说分析源代码能有多深入。因为看不懂啊。这时会有种遇到瓶颈的感觉。类似玩劲乐团的人，玩到一定程度，眼睛能跟上，但手速跟不上了。</div></li><li>注意，算法虽然是内功，但不是全部，还有很多知识是非常重要的，值得学习的，跟算法关系不太大的。比如设计模式，面向对象思想。所以算法学习到什么程度，自己酌情处理。毕竟越深入，会发现数学知识可能遇到瓶颈，但我想大多数人，只要不是搞科学研究，是不必深入到写龙格-库塔，FFT等算法的地步的。</li><li>总之深入学习算法的目的，对于程序员来说，是为了提高编程效率，提高解决问题的效率，能达到需要算法时，自己实现或找来能用的算法，很容易的嵌入到自己的程序中即可。</li></ol>
<div>&nbsp;</div>
<div>说说自己的学习，和强化路线吧，考虑到自己年事已高(28)，相比之下算法，数据结构基础未见得比少数玩ACM的大一（18）学生强。</div>
<div>自信一点！如果真的多数大一学生比我强，那确实没法混了，转行的时候到了。呵呵。</div>
<div>当然不能妄自菲薄，要相信自己有这个学习能力，有这个潜质。相信自己的数学基础足够用，这点要感谢中国对中小学数学教育普及的深啊，</div>
<div>况且我也一直是数学方面的优等生。同时自己的编码，学习经验也将是事半功倍的最大帮助。</div>
<div>对内存的分析，编译器的使用，代码的细节，操作系统的运作原理等知识的理解都要好于大一学生。</div>
<div>虽然意识有点晚，但我看好这项技能，并希望拥有她，而且相信我可以通过努力实现目标。&nbsp;</div>
<div>&nbsp;</div>
<div>先定目标：</div>
<div>1 通过练习算法，提高分析问题，利用计算机解决问题的能力。</div>
<div>2 提高读代码，发现问题的能力。</div>
<div>3 提高对C++，C#等语言的运用能力，如STL的应用。C++各种语法细节的理解。</div>
<div>&nbsp;</div>
<div>方法：练习+看书+做题+实战。</div>
<div>1. 练习常用数据结构，算法的实现，如，链表，队列，二叉树，排序，图等。以及下面说的第一阶段内容。</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;要求代码实现，用C，C++，C#均可，还要能用STL实现。总之，越熟越好。能盲打最高境界了。到这个程度，算法内功对我来说，应付各种工作都足够用了。</div>
<div>2. 不断重新看数据结构，算法的讲解，从中更深刻的理解每种算法的核心思想。</div>
<div>3. 练习常用算法，看书，很容易过度训练，然后恶心。一个容易激发热情的方式是做题，ACM，topcoder等平台，都有良好的积分评级政策。还有就是笔试题。这个只在处于找工作期间有很大动力。</div>
<div>&nbsp;&nbsp; 没看到ACM题库中又多了一个绿色的对号，自己的blog又多了些人来访问，等级提高都会有一种潜在的成就感，荣誉感萌发。这些虚拟的等级就是源动力。</div>
<div>4. 写总结，1，2，3如果都不能激发你的潜在兴趣了，实在编恶心了，那就把感受，辛酸苦辣，收获写出来与大伙分享吧。同时也是对自己的过去进行回忆，发现自己的进步之处。</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;不断给自己找出新的理由去继续学习。最重要的，这也是一个知识储备，构建自己的knowledge base的过程。对你未来的工作绝对是最宝贵，熟悉的财富。</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;比如，万一你将来够牛了，想出书了，这些一点一滴的积累过程将是再好不过的素材了。</div>
<div>&nbsp;</div>
<div>量化目标：</div>
<div>我一向认为能将质变效果量化了是一种很好的创新方式。因为他提供了一条完成的路。而且符合现代人，现代社会的价值观。</div>
<div>功成名就，无可厚非，这是一个大好的结果，如果办到，是千万老百姓都在寻找的答案。可惜每个成功人事的路都无法得到复制。</div>
<div>新东方老师曾问在做的学生，想GRE取得高分，拿奖学金么？ 当然想。</div>
<div>答案：熟背2万英语单词，得2万美刀，背的过程中去想1个单词就是1刀，全部完成后才能兑现。 </div>
<div>这个例子在我印象中很多年，一直是我认为将质变量化的最为典型，贴切的例子。</div>
<div>理想，梦想，高薪，富足生活，都可以看作一种质变，而努力奋斗的生活就是量化的过程。不同的是有人提前知道路在哪里，有人走着走着才知道。</div>
<div>有人虽然知道路，但怕黑怕孤独不愿走，有人坚持下去了，走到了最后；有人走着走着发现走错路了，有人走着走着庆幸的发现走对路了。</div>
<div>很难说，哪条路好走，哪条路是对的， 相比之下我更倾向于能看到结果的路，这可能就是老人说的，要有个奔头吧。</div>
<div>&nbsp;</div>
<div>1 TopCoder上250的题目（包括读题），曾有个人说20分钟能搞定去Google不成问题。我试过些，包括读题还是比较有难度，所以现实点吧：30分钟内搞定。</div>
<div>2 做完500 ACM题目。</div>
<div>3 如果能做到1，2相信算法能力已经有小小质变了。再加个基础要求吧，对于常用算法能40分钟内在纸上完成代码。</div>
<div>&nbsp;</div>
<div>另外转一个网上的评述：</div>
<blockquote style="margin-right: 0px" dir="ltr">
<div>
<div>
<p class="ContentTitle">一般要做到50行以内的程序不用调试、100行以内的二分钟内调试成功.acm主要是考算法的，&nbsp; </p>
<div>&nbsp;</div>
<div>主要时间是花在思考算法上，不是花在写程序与debug上。&nbsp;&nbsp;&nbsp;</div>
<div>下面给个计划你练练：&nbsp;&nbsp;&nbsp;</div>
<div>第一阶段：练经典常用算法，下面的每个算法给我打上十到二十遍，同时自己精简代码，因为太常用，所以要练到写时不用想，10-15分钟内打完，甚至关掉显示器都可以把程序打出来.&nbsp;&nbsp;&nbsp;</div>
<div>1.最短路(Floyd、Dijstra,BellmanFord)&nbsp;&nbsp;&nbsp;</div>
<div>2.最小生成树(先写个prim,kruscal要用并查集，不好写)&nbsp;&nbsp;&nbsp;</div>
<div>3.大数（高精度）加减乘除&nbsp;&nbsp;&nbsp;</div>
<div>4.二分查找. (代码可在五行以内)&nbsp;&nbsp;&nbsp;</div>
<div>5.叉乘、判线段相交、然后写个凸包.&nbsp;&nbsp;&nbsp;</div>
<div>6.BFS、DFS,同时熟练hash表(要熟，要灵活，代码要简)&nbsp;&nbsp;&nbsp;</div>
<div>7.数学上的有：辗转相除（两行内），线段交点、多角形面积公式.&nbsp;&nbsp;&nbsp;</div>
<div>8. 调用系统的qsort, 技巧很多，慢慢掌握。&nbsp;&nbsp;&nbsp;</div>
<div>9. 任意进制间的转换&nbsp;</div>
<div>&nbsp;</div>
<div>第二阶段：练习复杂一点，但也较常用的算法。&nbsp;&nbsp;&nbsp;</div>
<div>如：&nbsp;&nbsp;&nbsp;</div>
<div>1. 二分图匹配（匈牙利），最小路径覆盖&nbsp;&nbsp;&nbsp;</div>
<div>2. 网络流，最小费用流。&nbsp;&nbsp;&nbsp;</div>
<div>3. 线段树.&nbsp;&nbsp;&nbsp;</div>
<div>4. 并查集。&nbsp;&nbsp;&nbsp;</div>
<div>5. 熟悉动态规划的各个典型：LCS、最长递增子串、三角剖分、记忆化dp&nbsp;&nbsp;&nbsp;</div>
<div>6. 博弈类算法。博弈树，二进制法等。&nbsp;&nbsp;&nbsp;</div>
<div>7. 最大团，最大独立集。&nbsp;&nbsp;&nbsp;</div>
<div>8. 判断点在多边形内。&nbsp;&nbsp;&nbsp;</div>
<div>9. 差分约束系统.&nbsp;&nbsp;&nbsp;</div>
<div>10. 双向广度搜索、A*算法，最小耗散优先.&nbsp;</div></div></div></blockquote>
<div>时间：</div>
<div>人都是总结，展望容易，靠想靠说当然容易些，尤其是技术人员。真的去做，去完成却是最难的。所以上面说了一大堆，真正最后能实现多少，都是未知数。定些计划，往往能激发自己去完成，如果再把这个计划公开，那就更能加上点督促的力量。2-3年吧，是个比较合理的估计，那时工作也快满5年了。应该有一定积累了，也是质变的时候了。</div>
<div id="sharePanel" class="share_buttons"></div><img src ="http://www.cppblog.com/jackdongy/aggbug/197110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2013-01-08 14:56 <a href="http://www.cppblog.com/jackdongy/archive/2013/01/08/197110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何使用ACM练习算法 </title><link>http://www.cppblog.com/jackdongy/archive/2013/01/08/197109.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Tue, 08 Jan 2013 06:02:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2013/01/08/197109.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/197109.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2013/01/08/197109.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/197109.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/197109.html</trackback:ping><description><![CDATA[<p><br /><br />简单介绍下ACM，汗！还得现搜索一下。</p>
<p>ACM(Association for Computing Machinery)国际计算机组织</p>
<p>通常说的ACM是指 ACM国际大学生程序设计竞赛<br />基本可以看作是写各种算法的比赛。</p>
<p>&nbsp;</p>
<p>国内常用的ACM练习站：北大的比较有人气。<a href="http://acm.pku.edu.cn/JudgeOnline/">http://acm.pku.edu.cn/JudgeOnline/</a><br /><a href="http://poj.org/">http://poj.org/</a><br /></p>
<p>刚刚注册了下，体验了一下流程。</p>
<p>1 先Register一个账户，需要提交些个人信息，没啥顾虑就写真名吧。</p>
<p>2 到Problems里面查阅题目。可以先按1000的提示练习下。</p>
<p>3 在Submit Problem中写入解题代码，以C++格式提交。比如针对题目1000的，C++代码是</p>
<p style="padding-left: 30px"><span style="color: rgb(0,128,128)">#include </span>&lt;iostream&gt;<br /><span style="font-weight: bold; color: rgb(0,0,128)">using </span><span style="font-weight: bold; color: rgb(0,0,128)">namespace</span> std;<br /><br /><span style="font-weight: bold; color: rgb(0,0,128)">int </span>main(<span style="font-weight: bold; color: rgb(0,0,128)">int</span> argc, <span style="font-weight: bold; color: rgb(0,0,128)">const</span> <span style="font-weight: bold; color: rgb(0,0,128)">char</span>** argv) <br />{<br /><span style="font-weight: bold; color: rgb(0,0,128)">&nbsp;&nbsp; int</span> a, b; <br />&nbsp;&nbsp; cin &gt;&gt;a &gt;&gt; b;<br />&nbsp;&nbsp; cout &lt;&lt; a+b &lt;&lt;endl;<br />&nbsp;&nbsp; <span style="font-weight: bold; color: rgb(0,0,128)">return</span> <span style="color: rgb(0,0,255)">0</span>;<br />}</p>
<p>&nbsp;</p>
<p><span style="font-size: x-small">4 然后界面回显示你提交信息的状态，网站会自动刷新。如果有错，可以查看Compile Error。</span></p>
<p>
<p><span style="font-size: x-small">&nbsp;&nbsp; 直到显示蓝色的<span style="color: rgb(51,102,255)">Accepted<span style="color: rgb(0,0,0)">表示通过。</span></span></span></p>
<p><span style="font-size: x-small"><span style="color: rgb(51,102,255)"><span style="color: rgb(0,0,0)">5 你可以在User 栏中选择自己的ID，查看信息，比如我刚解决一道题目后，会显示。</span></span></span></p>
<p><span style="font-size: x-small"><span style="color: rgb(51,102,255)"></span></span></p>
<p>&nbsp;</p>
<p><span style="font-size: x-small"><span style="color: rgb(51,102,255)"><span style="color: rgb(0,0,0)"></span></span></span>
<table style="border-collapse: collapse; width: 700px" bordercolor="#ffffff" cellspacing="0" cellpadding="0" background="images/table_back.jpg" border="1">
<tbody>
<tr>
<td width="15%" align="left">Rank:</td>
<td width="25%" align="center"><span style="color: rgb(255,0,0)">50702</span></td>
<td width="60%" align="center">Solved Problems List</td></tr>
<tr>
<td width="15%" align="left">Solved:</td>
<td width="25%" align="center"><a href="http://blog.csdn.net/midgard/article/details/status?result=0&amp;user_id=midgard">1</a></td>
<td rowspan="4" width="60%" align="center"><a href="http://blog.csdn.net/midgard/article/details/problem?id=1000">1000 </a></td></tr>
<tr>
<td width="15%" align="left">Submissions:</td>
<td width="25%" align="center"><a href="http://blog.csdn.net/midgard/article/details/status?user_id=midgard">2</a></td></tr>
<tr>
<td width="15%" align="left">School:</td>
<td width="25%" align="center">&#215;&#215;&#215;</td></tr>
<tr>
<td width="15%" align="left">Email:</td>
<td width="25%" align="center">&#215;&#215;&#215;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#215;&#215;&#215;&#64;&#215;&#215;&#46;&#99;&#111;&#109;">@&#215;&#215;.com</a> </td></tr></tbody></table>
<p>&nbsp;</p>
<p>6 应该解决问题越多，排名越高，积分越多吧。挺有趣的。 据说练习的人都很上瘾，尝试了下发现确实在线的人很多，以后再做做。</p>
<p>&nbsp;</p>
<p>另外国际上也有个网站比较适合练习算法， <span style="color: rgb(51,153,102)">topcoder</span>， 择日介绍下。<br /><a href="http://blog.csdn.net/midgard/article/details/4073319">http://blog.csdn.net/midgard/article/details/4073319</a></p> <img src ="http://www.cppblog.com/jackdongy/aggbug/197109.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2013-01-08 14:02 <a href="http://www.cppblog.com/jackdongy/archive/2013/01/08/197109.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>RMQ算法 </title><link>http://www.cppblog.com/jackdongy/archive/2012/12/17/196369.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Mon, 17 Dec 2012 02:45:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/12/17/196369.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/196369.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/12/17/196369.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/196369.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/196369.html</trackback:ping><description><![CDATA[<a href="http://blog.csdn.net/liang5630/article/details/7917702">http://blog.csdn.net/liang5630/article/details/7917702</a><br /><br /><span style="padding-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; padding-right: 0px"><strong>1. 概述</strong></span> 
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">RMQ（Range Minimum/Maximum Query），即区间最值查询，是指这样一个问题：对于长度为n的数列A，回答若干询问RMQ（A,i,j）(i,j&lt;=n)，返回数列A中下标在i，j之间的最小/大值。这两个问题是在实际应用中经常遇到的问题，下面介绍一下解决这两种问题的比较高效的算法。<span style="font-family: 'Lucida Grande','Lucida Sans Unicode',Verdana,sans-serif; line-height: 24px; background-color: rgb(247,243,237)">当然，该问题也可以用线段树（也叫区间树）解决，算法复杂度为：O(N)~O(logN)，这里我们暂不介绍。</span></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px"><br /></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px"><span style="padding-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; padding-right: 0px"><strong>2.RMQ算法</strong></span></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">对于该问题，最容易想到的解决方案是遍历，复杂度是O(n)。但当数据量非常大且查询很频繁时，该算法无法在有效的时间内查询出正解。</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">本节介绍了一种比较高效的在线算法（ST算法）解决这个问题。所谓在线算法，是指用户每输入一个查询便马上处理一个查询。该算法一般用较长的时间做预处理，待信息充足以后便可以用较少的时间回答每个查询。ST（Sparse Table）算法是一个非常有名的在线处理RMQ问题的算法，它可以在O(nlogn)时间内进行预处理，然后在O(1)时间内回答每个查询。</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px"><br /></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px"><strong>（一）首先是预处理，用动态规划（DP）解决。</strong></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">设A[i]是要求区间最值的数列，<span>F[i, j]表示从第i个数起连续2^j个数中的最大值。（DP的状态）</span></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">例如：</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">A数列为：3 2 4 5 6 8 1 2 9 7</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">F[1，0]表示第1个数起，长度为2^0=1的最大值，其实就是3这个数。同理 F[1,1] = max(3,2) = 3, F[1，2]=max(3,2,4,5) = 5，F[1，3] = max(3,2,4,5,6,8,1,2) = 8;</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">并且我们可以容易的看出<span>F[i,0]就等于A[i]。（DP的初始值）</span></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">这样，DP的状态、初值都已经有了，剩下的就是状态转移方程。</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">我们把F[i，j]平均分成两段（因为f[i，j]一定是偶数个数字），从 i 到i + 2 ^ (j - 1) - 1为一段，i + 2 ^ (j - 1)到i + 2 ^ j - 1为一段(长度都为2 ^ (j - 1))。用上例说明，当i=1，j=3时就是3,2,4,5 和 6,8,1,2这两段。F[i，j]就是这两段各自最大值中的最大值。于是我们得到了<span>状态转移方程F[i, j]=max（F[i，j-1], F[i + 2^(j-1)，j-1]）。</span></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">代码如下：</p>
<p>&nbsp;</p>
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/liang5630/article/details/7917702#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/liang5630/article/details/7917702#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/liang5630/article/details/7917702#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/liang5630/article/details/7917702#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="keyword">void</span><span>&nbsp;RMQ(</span><span class="datatypes">int</span><span>&nbsp;num)&nbsp;</span><span class="comment">//预处理-&gt;O(nlogn)</span><span>&nbsp;&nbsp;</span></li><li><span>{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="datatypes">int</span><span>&nbsp;j&nbsp;=&nbsp;1;&nbsp;j&nbsp;&lt;&nbsp;20;&nbsp;++j)&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="datatypes">int</span><span>&nbsp;i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;=&nbsp;num;&nbsp;++i)&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(i&nbsp;+&nbsp;(1&nbsp;&lt;&lt;&nbsp;j)&nbsp;-&nbsp;1&nbsp;&lt;=&nbsp;num)&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxsum[i][j]&nbsp;=&nbsp;max(maxsum[i][j&nbsp;-&nbsp;1],&nbsp;maxsum[i&nbsp;+&nbsp;(1&nbsp;&lt;&lt;&nbsp;(j&nbsp;-&nbsp;1))][j&nbsp;-&nbsp;1]);&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;minsum[i][j]&nbsp;=&nbsp;min(minsum[i][j&nbsp;-&nbsp;1],&nbsp;minsum[i&nbsp;+&nbsp;(1&nbsp;&lt;&lt;&nbsp;(j&nbsp;-&nbsp;1))][j&nbsp;-&nbsp;1]);&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">void RMQ(int num) //预处理-&gt;O(nlogn)
{
	for(int j = 1; j &lt; 20; ++j)
		for(int i = 1; i &lt;= num; ++i)
			if(i + (1 &lt;&lt; j) - 1 &lt;= num)
			{
				maxsum[i][j] = max(maxsum[i][j - 1], maxsum[i + (1 &lt;&lt; (j - 1))][j - 1]);
				minsum[i][j] = min(minsum[i][j - 1], minsum[i + (1 &lt;&lt; (j - 1))][j - 1]);
			}
}</pre>
<p><br /><span>这里我们需要注意的是循环的顺序，我们发现外层是j，内层所i，这是为什么呢？可以是i在外，j在内吗？</span></p>
<p>&nbsp;</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px"><br /></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">答案是不可以。因为我们需要理解这个状态转移方程的意义。</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">状态转移方程的含义是：先更新所有长度为F[i,0]即1个元素，然后通过2个1个元素的最值，获得所有长度为F[i,1]即2个元素的最值，然后再通过2个2个元素的最值，获得所有长度为F[i,2]即4个元素的最值，以此类推更新所有长度的最值。</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">而如果是i在外，j在内的话，我们更新的顺序就是F[1,0],F[1,1],F[1,2],F[1,3],表示更新从1开始1个元素，2个元素，4个元素，8个元素（A[0],A[1],....A[7]）的最值，这里F[1,3] = max(max(A[0],A[1],A[2],A[3]),max(A[4],A[5],A[6],A[7]))的值，但是我们根本没有计算max(A[0],A[1],A[2],A[3])和max(A[4],A[5],A[6],A[7])，所以这样的方法肯定是错误的。</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px"><br /></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">为了避免这样的错误，一定要好好理解这个状态转移方程所代表的含义。</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px"><strong><br /></strong></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px"><strong><br /></strong></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px"><strong>（二）然后是查询。</strong></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">假如我们需要查询的区间为(i,j)，那么我们需要找到覆盖这个闭区间(左边界取i，右边界取j)的最小幂（可以重复，比如查询5，6，7，8，9，我们可以查询5678和6789）。</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">因为这个区间的长度为j - i + 1,所以我们可以取k=log2( j - i + 1)，则有：RMQ(A, i, j)=max{F[i , k], F[ j - 2 ^ k + 1, k]}。</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">举例说明，要求区间[2，8]的最大值，k = log2（8 - 2 + 1）= 2，即求max(F[2, 2]，F[8 - 2 ^ 2 + 1, 2]) = max(F[2, 2]，F[5, 2])；</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px"><br /></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">在这里我们也需要注意一个地方，就是&lt;&lt;运算符和+-运算符的优先级。</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">比如这个表达式：5 - 1 &lt;&lt; 2是多少？</p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px"><br /></p>
<p style="list-style-type: none; margin-bottom: 0px; padding-bottom: 0px; padding-top: 0px; margin-top: 0px">答案是：4 * 2 * 2 = 16。所以我们要写成5 - (1 &lt;&lt; 2)才是5-1 * 2 * 2 = 1。</p><img src ="http://www.cppblog.com/jackdongy/aggbug/196369.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-12-17 10:45 <a href="http://www.cppblog.com/jackdongy/archive/2012/12/17/196369.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MF算法 --- 传说后缀数组中最快的构建法</title><link>http://www.cppblog.com/jackdongy/archive/2012/11/20/195409.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Tue, 20 Nov 2012 07:21:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/11/20/195409.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/195409.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/11/20/195409.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/195409.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/195409.html</trackback:ping><description><![CDATA[<p>Giovanni Manzini and Paolo Ferragina 吸取了前人多种经验,结合n个算法,组建了最快的sa构建法.2005年新出的算法.是GNU开源项目,竞赛中 1000万的数据是 1 s,文件相当多,不能写在博客里,linux源码可以看:</p>
<p>http://www.mfn.unipmn.it/~manzini/lightweight</p>
<p>如果不会用,就下载本C++ 多串匹配程序包吧</p><br /><a style="color: " href="/Files/jackdongy/MF串行.zip">下载程序</a> <br /><br /><br /><a href="http://download.csdn.net/download/tiandyoin/1607178">http://download.csdn.net/download/tiandyoin/1607178</a><img src ="http://www.cppblog.com/jackdongy/aggbug/195409.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-11-20 15:21 <a href="http://www.cppblog.com/jackdongy/archive/2012/11/20/195409.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>