﻿<?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++博客-游戏人生</title><link>http://www.cppblog.com/Fox/</link><description>游戏人生 != ( 人生 == 游戏 )</description><language>zh-cn</language><lastBuildDate>Sat, 17 May 2008 16:16:20 GMT</lastBuildDate><pubDate>Sat, 17 May 2008 16:16:20 GMT</pubDate><ttl>60</ttl><item><title>周记：找回激情</title><link>http://www.cppblog.com/Fox/archive/2008/05/11/find_enthusiasm.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Sat, 10 May 2008 18:25:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/05/11/find_enthusiasm.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/49491.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/05/11/find_enthusiasm.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/49491.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/49491.html</trackback:ping><description><![CDATA[<p>写的太杂，实在没法写题目，就用这一周的签名吧，很合现在的心境。
<p><a href="http://www.cppblog.com/kevinlynx/" target=_blank>Kevin</a>眼中的我，大概是个<font color=#800000>重视理论算法胜过编程实践</font>的人，而我的算法和理论基础尚差的出奇（可能这就是知耻而后勇吧:D），可见我的编程实践又会多么的差了。<a href="http://www.cppblog.com/Bugs/" target=_blank>Bugs</a>更是对我整日沉浸于这些不着边际的&#8220;<font color=#800000>空中楼阁</font>&#8221;颇有微词，甚至嗤之以鼻。今日若不是要把自己前段时间的豆腐渣粉饰一番，我依然不愿去考虑多线程的具体实现，或者说不是不愿，是不敢，总有一种<font color=#800000>临深履薄</font>之感。
<p>纵然如此，为了更好的完成工作，我还是拉来Kevin，劳他为我讲解一下<a href="http://en.wikipedia.org/wiki/Multithread" target=_blank>多线程</a>，可能是因为我从未仔细看过<a href="http://en.wikipedia.org/wiki/Boost_C%2B%2B_Libraries" target=_blank>boost</a>等C++开源库的原因吧，我对于结构封装本身并没有多少概念。说句实话，看到那些模板我就头大，心里想：本来一个简单的东西，为什么要搞的那么复杂呢？当然，我知道，这是因为我对其<font color=#800000>缺乏了解</font>，在对一样东西没有完全理解就妄测其好坏是自卑的表现:D，所以也请Kevin原谅我的无知，顺便致谢;-)。
<p>还是稍微提一下多线程的东西吧，因为这一次改动并不很大，因此只言片语难以面面俱到，也请各位TX不必较真儿。这儿只是说一下我是怎么偷懒把之前没有使用多线程的I/O部分修改成多线程I/O的，I/O的细节不再详述，而且这台机器上面因为没有VS，仅凭记忆，如果有什么差错，请帮我指出来了:-)。
<p>在项目启动后的初始化中初始化I/O线程： </p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: courier new; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;SomeApp::Init(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">{&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;do&nbsp;some&nbsp;other&nbsp;things&nbsp;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;CIOOperator::Init();&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;InitializeCriticalSection&nbsp;for&nbsp;I/O&nbsp;queue(s)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">nIOThreadsNum;&nbsp;</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">i&nbsp;)&nbsp;<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CIOOperator&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pOpObj&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;CIOOperator;&nbsp;<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pOpObj</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Create();&nbsp;<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_vecIOThreads.push_back(pOpObj);&nbsp;<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;do&nbsp;some&nbsp;other&nbsp;things&nbsp;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">}</span></div>
<p><br>在项目退出前结束I/O线程：&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: courier new; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;SomeApp::Release(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)&nbsp;<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">{&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;do&nbsp;some&nbsp;other&nbsp;things&nbsp;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;vector</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">CIOOperator&nbsp;</span><span style="COLOR: #000000">*&gt;</span><span style="COLOR: #000000">::iterator&nbsp;it&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;m_vecIOThreads.begin();&nbsp;<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(&nbsp;;&nbsp;i</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">m_vecIOThreads.end();&nbsp;</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">it&nbsp;)&nbsp;<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;it</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">End();&nbsp;<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">it);&nbsp;<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;m_vecIOThreads.clear();<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;CIOOperator::Release();&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;DeleteCriticalSectionfor&nbsp;I/O&nbsp;queue(s)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;do&nbsp;some&nbsp;other&nbsp;things&nbsp;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">}&nbsp;</span></div>
<p><br>I/O线程函数：&nbsp;&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: courier new; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;ThreadFunc(&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pArgument&nbsp;)<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;do&nbsp;some&nbsp;other&nbsp;things,&nbsp;like&nbsp;exception&nbsp;handling&nbsp;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;(CIOOperator&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)pArgument</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Run();&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;operating&nbsp;I/O&nbsp;queue(s)&nbsp;until&nbsp;exit</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;do&nbsp;some&nbsp;other&nbsp;things&nbsp;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;_endthreadex();<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<p>说多线程复杂，无外乎线程的<font color=#800000>退出策略</font>、<font color=#800000>同步机制</font>、<font color=#800000>调试</font>、<font color=#800000>异常处理</font>等等。多少还是需要一些知识（尤其是同步）和经验（尤其是<font color=#800000>调试</font>）。</p>
<p>再回来说一下最近比较关注的算法吧，虽然为某些人所不齿，甚至公然批评我最近比较松懈，实在令我难堪的紧。我又没有消极怠工，难道编写代码是积极，学习算法就是消极吗？乡下来的，且不必理他。当然，多少还是需要注意一下分寸吧。</p>
<p>在受到上次解决<a href="http://www.cppblog.com/Fox/archive/2008/04/20/flapjack_sortting.html">烙饼排序问题</a>的打击之后，我开始反思：自己思考和解决问题的角度怎么就那么简单和狭隘？细细想来，从本科毕业之后，几乎再没翻过算法的书，几乎再没做过算法的题，写代码只是为了糊口，只能糊口的代码自然只能以垃圾形容。意识粗糙，操作离谱，整个一下里巴人。
<p>在一番深深的自责之后，痛定思痛，痛何如哉，才感觉自己关于算法的思维空间已经局限于if-else、do-while，连穷举、分治、贪心、回溯这些以前念书时天天挂在嘴边侃侃而谈的常用算法都没有概念了，遑论动态规划、最小二乘法、线性回归等复杂一些的（非）数值算法，关于数据结构的思维空间也已经局限于vector、list、map了，再也没有回忆过stack、tree、graph这些读死书、死读书得来的所谓知识。&nbsp;
<p>可悲啊，为什么拿到一个困难一点的问题，就只知道画图、编码，而不知道组织算法呢？甚至连这个问题到底有无多项式时间解都不去考虑。然而，一提谁都知道：<font color=#800000>算法复杂性</font>——数据结构第0章就会提到的基础，真正分析起来，却是力不从心。
<p>所以，接着扫扫盲吧，实在没有必要去搞很多艰深的东西，本来想接下来就写<a href="http://en.wikipedia.org/wiki/NP_%28complexity%29" target=_blank>NP难题</a>，可是近来工作上的事情确实有些多，之前一篇已经是被<a href="http://www.cppblog.com/Alex/" target=_blank>Alex</a>（这家伙却至今未开张&#8230;&#8230;）&#8220;催出来&#8221;的了。</p>
<p>手头只有MIT英文版的《<a href="http://mitpress.mit.edu/algorithms/">Introduction to Algorithms</a>》ed.2，于是就从网上找了中文电子版，居然是上个世纪94年南京大学译的第一版。看算法的话，多半是以这本书和<a href="http://en.wikipedia.org/wiki/Wikipedia" target=_blank>Wikipedia</a>为主了。</p>
<p>PS: 另外做的一点事情，似乎和<a href="http://en.wikipedia.org/wiki/Lexical_analysis" target=_blank>词法分析</a>、<a href="http://en.wikipedia.org/wiki/Exception_handling" target=_blank>异常处理</a>等多少有些关联，内容相当琐碎，此刻不再赘述。</p>
<p>对了，和工作、学习并不那么相干的事情就是，今天和几个同事出去钓了几个小时鱼，收获嘛，保密:D。</p>
<p>近期考虑的关键词：无缝世界 网游安全 算法导论 兄弟激情</p><img src ="http://www.cppblog.com/Fox/aggbug/49491.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-05-11 02:25 <a href="http://www.cppblog.com/Fox/archive/2008/05/11/find_enthusiasm.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>动态规划算法</title><link>http://www.cppblog.com/Fox/archive/2008/05/07/Dynamic_programming.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Wed, 07 May 2008 12:43:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/05/07/Dynamic_programming.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/49153.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/05/07/Dynamic_programming.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/49153.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/49153.html</trackback:ping><description><![CDATA[<p>以前在学习非数值算法的时候，曾经了解过<a href="http://en.wikipedia.org/wiki/Dynamic_programming" target="_blank">动态规划算法（Dynamic programming）</a>，以下是对<a href="http://en.wikipedia.org/wiki/Main_Page" target="_blank">Wikipedia</a>上<a href="http://en.wikipedia.org/wiki/Dynamic_programming" target="_blank">动态规划</a>的翻译，图也是<a href="http://en.wikipedia.org/wiki/Main_Page" target="_blank">Wikipedia</a>上的，仓促行文，不到之处，请方家指正。</p> <p>这篇文章的术语实在是太多了，所以我在文中加入了少量注释，一律以<em><strong>粗斜体</strong></em>注明。</p> <p>本文的不足之处将<strong>随时修正</strong>，MIT的《<a href="http://mitpress.mit.edu/algorithms/" target="_blank">Introduction to Algorithms</a>》第15章是专门讲动态规划的。</p> <p>_____________________________________________________________</p> <p align="center"><strong><a href="http://en.wikipedia.org/wiki/Dynamic_programming" target="_blank">动态规划</a></strong></p> <p>在数学与计算机科学领域，<strong>动态规划</strong>用于解决那些可分解为<a href="http://en.wikipedia.org/wiki/Overlapping_subproblem" target="_blank">重复子问题</a>（overlapping subproblems，<em><strong>想想递归求阶乘吧</strong></em>）并具有<a href="http://en.wikipedia.org/wiki/Optimal_substructure" target="_blank">最优子结构</a>（optimal substructure，<strong><em>想想最短路径算法</em></strong>）（如下所述）的问题，动态规划比通常算法花费更少时间。  <p>上世纪40年代，<a href="http://en.wikipedia.org/wiki/Richard_Bellman" target="_blank">Richard Bellman</a>最早使用动态规划这一概念表述通过遍历寻找最优决策解问题的求解过程。1953年，Richard Bellman将动态规划<a href="http://www.wu-wien.ac.at/usr/h99c/h9951826/bellman_dynprog.pdf" target="_blank">赋予现代意义</a>，该领域被IEEE纳入系统分析和工程中。为纪念Bellman的贡献，动态规划的核心方程被命名为<a href="http://en.wikipedia.org/wiki/Bellman_equation" target="_blank">贝尔曼方程</a>，该方程以<a href="http://en.wikipedia.org/wiki/Recursion" target="_blank">递归</a>形式重申了一个优化问题。  <p>在“动态规划”（dynamic programming）一词中，programming与“计算机编程”（computer programming）中的programming并无关联，而是来自“<a href="http://en.wikipedia.org/wiki/Mathematical_programming" target="_blank">数学规划</a>”（mathematical programming），也称优化。因此，规划是指对生成活动的优化策略。举个例子，编制一场展览的日程可称为规划。 在此意义上，规划意味着找到一个可行的活动计划。  <ul> <li> <div align="left"><strong>概述</strong></div></li></ul> <p><img style="margin: 10px" src="http://upload.wikimedia.org/wikipedia/en/4/42/Shortest_path_optimal_substructure.png" align="left">  <p><strong></strong>&nbsp; <p><strong>图1</strong> 使用最优子结构寻找最短路径：直线表示边，波状线表示两顶点间的最短路径（路径中其他节点未显示）；粗线表示从起点到终点的最短路径。  <p><strong><em>不难看出，start到goal的最短路径由start的相邻节点到goal的最短路径及start到其相邻节点的成本决定。</em></strong>  <p><strong><em></em></strong>&nbsp; <p>&nbsp; <p>最优子结构即可用来寻找整个问题最优解的子问题的最优解。举例来说，寻找<a href="http://en.wikipedia.org/wiki/Graph_%28mathematics%29" target="_blank">图</a>上某顶点到终点的<a href="http://en.wikipedia.org/wiki/Shortest_path_problem" target="_blank">最短路径</a>，可先计算该顶点所有相邻顶点至终点的最短路径，然后以此来选择最佳整体路径，如<strong>图1</strong>所示。  <p>一般而言，最优子结构通过如下三个步骤解决问题：  <p>a) 将问题分解成较小的子问题；  <p>b) 通过递归使用这三个步骤求出子问题的最优解；  <p>c) 使用这些最优解构造初始问题的最优解。  <p>子问题的求解是通过不断划分为更小的子问题实现的，直至我们可以在常数时间内求解。  <p><img style="margin: 10px" src="http://upload.wikimedia.org/wikipedia/commons/thumb/0/06/Fibonacci_dynamic_programming.svg/108px-Fibonacci_dynamic_programming.svg.png" align="left">  <p><strong></strong>&nbsp; <p><strong></strong>&nbsp; <p><strong>图2</strong> Fibonacci序列的子问题示意图：使用<a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph" target="_blank">有向无环图</a>（DAG, directed acyclic graph）而非<a href="http://en.wikipedia.org/wiki/Tree_structure" target="_blank">树</a>表示重复子问题的分解。  <p><strong><em>为什么是DAG而不是树呢？答案就是，如果是树的话，会有很多重复计算，下面有相关的解释。</em></strong>  <p>&nbsp; <p>&nbsp; <p>一个问题可划分为重复子问题是指通过相同的子问题可以解决不同的较大问题。例如，在Fibonacci序列中，F3 = F1 + F2和F4 = F2 + F3都包含计算F2。由于计算F5需要计算F3和F4，一个比较笨的计算F5的方法可能会重复计算F2两次甚至两次以上。这一点对所有重复子问题都适用：愚蠢的做法可能会为重复计算已经解决的最优子问题的解而浪费时间。  <p>为避免重复计算，可将已经得到的子问题的解保存起来，当我们要解决相同的子问题时，重用即可。该方法即所谓的<a href="http://en.wikipedia.org/wiki/Memoization" target="_blank">缓存</a>（memoization，而不是存储memorization，虽然这个词亦适合，<strong><em>姑且这么叫吧，这个单词太难翻译了，简直就是可意会不可言传，其意义是没计算过则计算，计算过则保存</em></strong>）。当我们确信将不会再需要某一解时，可以将其抛弃，以节省空间。在某些情况下，我们甚至可以提前计算出那些将来会用到的子问题的解。  <p>总括而言，动态规划利用：  <p>1) <a href="http://en.wikipedia.org/wiki/Overlapping_subproblem" target="_blank">重复子问题</a>  <p>2) <a href="http://en.wikipedia.org/wiki/Optimal_substructure" target="_blank">最优子结构</a>  <p>3) <a href="http://en.wikipedia.org/wiki/Memoization" target="_blank">缓存</a>  <p>动态规划通常采用以下两种方式中的一种两个办法：  <p><a href="http://en.wikipedia.org/wiki/Top-down" target="_blank">自顶向下</a>：将问题划分为若干子问题，求解这些子问题并保存结果以免重复计算。该方法将递归和缓存结合在一起。  <p><a href="http://en.wikipedia.org/wiki/Bottom-up" target="_blank">自下而上</a>：先行求解所有可能用到的子问题，然后用其构造更大问题的解。该方法在节省堆栈空间和减少函数调用数量上略有优势，但有时想找出给定问题的所有子问题并不那么直观。  <p>为了提高<a href="http://en.wikipedia.org/wiki/Call-by-name" target="_blank">按名传递</a>（call-by-name，这一机制与<a href="http://en.wikipedia.org/wiki/Call-by-need" target="_blank">按需传递</a>call-by-need相关，<strong><em>复习一下参数传递的各种规则吧，简单说一下，按名传递允许改变实参值</em></strong>）的效率，一些编程语言将函数的返回值“自动”缓存在函数的特定参数集合中。一些语言将这一特性尽可能简化（如<a href="http://en.wikipedia.org/wiki/Scheme_%28programming_language%29" target="_blank">Scheme</a>、<a href="http://en.wikipedia.org/wiki/Common_Lisp" target="_blank">Common Lisp</a>和<a href="http://en.wikipedia.org/wiki/Perl" target="_blank">Perl</a>），也有一些语言需要进行特殊扩展（如C++，<strong><em>C++中使用的是按值传递和按引用传递，因此C++中本无自动缓存机制，需自行实现，具体实现的一个例子是<a href="http://www.apl.jhu.edu/~paulmac/c++-memoization.html" target="_blank">Automated Memoization in C++</a></em></strong>）。无论如何，只有<a href="http://en.wikipedia.org/wiki/Referential_transparency_%28computer_science%29" target="_blank">指称透明</a>（referentially transparent，<strong><em>指称透明是指在程序中使用表达式、函数本身或以其值替换对程序结果没有任何影响</em></strong>）函数才具有这一特性。  <ul> <li><strong>例子</strong> </li></ul> <p><strong>1. Fibonacci序列</strong>  <p>寻找<a href="http://en.wikipedia.org/wiki/Fibonacci_sequence" target="_blank">Fibonacci序列</a>中第n个数，基于其数学定义的直接实现：  <p>&nbsp;&nbsp; function fib(n)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if n = 0 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if n = 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return fib(n-1) + fib(n-2)  <p>如果我们调用fib(5)，将产生一棵对于同一值重复计算多次的调用树：  <ol> <li>fib(5)  <li>fib(4) + fib(3)  <li>(fib(3) + fib(2)) + (fib(2) + fib(1))  <li>((fib(2) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))  <li>(((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1)) </li></ol> <p>特别是，fib(2)计算了3次。在更大规模的例子中，还有更多fib的值被重复计算，将消耗指数级时间。  <p>现在，假设我们有一个简单的<a href="http://en.wikipedia.org/wiki/Associative_array" target="_blank">映射</a>（map）对象<em>m</em>，为每一个计算过的fib及其返回值建立映射，修改上面的函数fib，使用并不断更新<em>m</em>。新的函数将只需<em>O</em>(<em>n</em>)的时间，而非指数时间：  <p>&nbsp;&nbsp; var m := map(0 → 1, 1 → 1)<br>&nbsp;&nbsp; function fib(n)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if map m does not contain key n<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m[n] := fib(n-1) + fib(n-2)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m[n]  <p>这一保存已计算出的数值的技术即被称为<a href="http://en.wikipedia.org/wiki/Memoization" target="_blank">缓存</a>，这儿使用的是<strong>自顶向下</strong>的方法：先将问题划分为若干子问题，然后计算和存储值。  <p>在<strong>自下而上</strong>的方法中，我们先计算较小的fib，然后基于其计算更大的fib。这种方法也只花费线性（<em>O</em>(<em>n</em>)）时间，因为它包含一个<em>n</em>-1次的循环。然而，这一方法只需要常数（<em>O</em>(1)）的空间，相反，<strong>自顶向下</strong>的方法则需要O(<em>n</em>)的空间来储存映射关系。  <p>&nbsp;&nbsp; function fib(n)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var previousFib := 0, currentFib := 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if n = 0 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if n = 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; repeat n-1 times<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var newFib := previousFib + currentFib<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; previousFib := currentFib<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentFib&nbsp; := newFib<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return currentFib  <p>在这两个例子，我们都只计算fib(2)一次，然后用它来计算fib(3)和fib(4)，而不是每次都重新计算。  <p><strong>2. 一种平衡的0-1矩阵</strong>  <p>考虑<em>n</em>*<em>n</em>矩阵的赋值问题：只能赋0和1，<em>n</em>为偶数，使每一行和列均含<em>n</em>/2个0及<em>n</em>/2个1。例如，当<em>n</em>=4时，两种可能的方案是：  <p>+ - - - - +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + - - - - +<br>| 0 1 0 1 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | 0 0 1 1 |<br>| 1 0 1 0 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | 0 0 1 1 |<br>| 0 1 0 1 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | 1 1 0 0 |<br>| 1 0 1 0 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | 1 1 0 0 |<br>+ - - - - +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + - - - - +  <p>问：对于给定<em>n</em>，共有多少种不同的赋值方案。  <p>至少有三种可能的算法来解决这一问题：<a href="http://en.wikipedia.org/wiki/Brute_force" target="_blank">穷举法</a>（brute force）、<a href="http://en.wikipedia.org/wiki/Backtracking" target="_blank">回溯法</a>（backtracking）及动态规划（dynamic programming）。穷举法列举所有赋值方案，并逐一找出满足平衡条件的方案。由于共有C(<em>n</em>, <em>n</em>/2)^<em>n</em>种方案（<strong><em>在一行中，含n/2个0及n/2个1的组合数为C(n,n/2)，相当于从n个位置中选取n/2个位置置0，剩下的自然是1</em></strong>），当<em>n</em>=6时，穷举法就已经几乎不可行了。回溯法先将矩阵中部分元素置为0或1，然后检查每一行和列中未被赋值的元素并赋值，使其满足每一行和列中0和1的数量均为<em>n</em>/2。回溯法比穷举法更加巧妙一些，但仍需遍历所有解才能确定解的数目，可以看到，当<em>n</em>=8时，该题解的数目已经高达116963796250。动态规划则无需遍历所有解便可确定解的数目（<strong><em>意思是划分子问题后，可有效避免若干子问题的重复计算</em></strong>）。  <p>通过动态规划求解该问题出乎意料的简单。考虑每一行恰含<em>n</em>/2个0和<em>n</em>/2个1的<em>k</em>*<em>n</em>(1&lt;=<em>k</em>&lt;=<em>n</em>)的子矩阵，函数f根据每一行的可能的赋值映射为一个向量，每个向量由<em>n</em>个整数对构成。向量每一列对应的一个整数对中的两个整数分别表示该列上该行以下已经放置的0和1的数量。该问题即转化为寻找f((<em>n</em>/2,<em>n</em>/2),(<em>n</em>/2,<em>n</em>/2),...,(<em>n</em>/2,<em>n</em>/2))（具有<em>n</em>个参数或者说是一个含<em>n</em>个元素的向量）的值。其子问题的构造过程如下：  <p>1) 最上面一行（<strong><em>第k行</em></strong>）具有C(<em>n</em>, <em>n</em>/2)种赋值；  <p>2) 根据最上面一行中每一列的赋值情况（为0或1），将其对应整数对中相应的元素值减1；  <p>3) 如果任一整数对中的任一元素为负，则该赋值非法，不能成为正确解；  <p>4) 否则，完成对<em>k</em>*<em>n</em>的子矩阵中最上面一行的赋值，取<em>k</em>=<em>k</em>-1，计算剩余的(<em>k</em>-1)*<em>n</em>的子矩阵的赋值；  <p>5) 基本情况是一个1*<em>n</em>的细小的子问题，此时，该子问题的解的数量为0或1，取决于其向量是否是<em>n</em>/2个(0, 1)和<em>n</em>/2个(1, 0)的排列。  <p>例如，在上面给出的两种方案中，向量序列为：  <p>((2, 2) (2, 2) (2, 2) (2, 2))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((2, 2) (2, 2) (2, 2) (2, 2))&nbsp;&nbsp;&nbsp;&nbsp; k = 4<br>&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1  <p><font color="#800000">((1, 2) (2, 1) (1, 2) (2, 1))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((1, 2) (1, 2) (2, 1) (2, 1))&nbsp;&nbsp;&nbsp;&nbsp; k = 3</font><br>&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1  <p>((1, 1) (1, 1) (1, 1) (1, 1))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((0, 2) (0, 2) (2, 0) (2, 0))&nbsp;&nbsp;&nbsp;&nbsp; k = 2<br>&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0  <p>((0, 1) (1, 0) (0, 1) (1, 0))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((0, 1) (0, 1) (1, 0) (1, 0))&nbsp;&nbsp;&nbsp;&nbsp; k = 1<br>&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0  <p>((0, 0) (0, 0) (0, 0) (0, 0))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((0, 0) (0, 0), (0, 0) (0, 0))  <p><strong><font color="#800000"><em>动态规划在此的意义在于避免了相同f的重复计算，更进一步的，上面着色的两个f，虽然对应向量不同，但f的值是相同的，想想为什么吧</em>:D<em>。</em></font></strong>  <p>该问题解的数量（序列a058527在OEIS）是1, 2, 90, 297200, 116963796250, 6736218287430460752, ...  <p>下面的外部链接中包含回溯法的Perl源代码实现，以及动态规划法的MAPLE和C语言的实现。  <p><strong>3. 棋盘</strong>  <p>考虑<em>n</em>*<em>n</em>的棋盘及成本函数C(<em>i</em>,<em>j</em>)，该函数返回方格(<em>i</em>,<em>j</em>)相关的成本。以5*5的棋盘为例：  <p>5 | 6 7 4 7 8<br>4 | 7 6 1 1 4<br>3 | 3 5 7 8 2<br>2 | 2 6 7 0 2<br>1 | 7 3 5 6 1<br>- + - - - - -<br>&nbsp; | 1 2 3 4 5  <p>可以看到：C(1,3)=5  <p>从棋盘的任一方格的第一阶（即行）开始，寻找到达最后一阶的最短路径（使所有经过的方格的成本之和最小），假定只允许向左对角、右对角或垂直移动一格。  <p>5 |<br>4 |<br>3 |<br>2 |&nbsp;&nbsp; x x x<br>1 |&nbsp;&nbsp;&nbsp;&nbsp; o<br>- + - - - - -<br>&nbsp; | 1 2 3 4 5  <p>该问题展示了最优子结构。即整个问题的全局解依赖于子问题的解。定义函数q(<em>i</em>,<em>j</em>)，令：q(<em>i</em>,<em>j</em>)表示到达方格(<em>i</em>,<em>j</em>)的最低成本。  <p>如果我们可以求出第<em>n</em>阶所有方格的q(<em>i</em>,<em>j</em>)值，取其最小值并逆向该路径即可得到最短路径。  <p>记q(<em>i</em>,<em>j</em>)为方格(<em>i</em>,<em>j</em>)至其下三个方格（<strong><em>(i-1,j-1)、(i-1,j)、(i-1,j+1)</em></strong>）最低成本与c(<em>i</em>,<em>j</em>)之和，例如：  <p>5 |<br>4 |&nbsp;&nbsp;&nbsp;&nbsp; <em>A</em><br>3 |&nbsp;&nbsp; <em>B C D<br></em>2 |<br>1 |<br>- + - - - - -<br>&nbsp; | 1 2 3 4 5  <p>q(<em>A</em>) = min(q(<em>B</em>),q(<em>C</em>),q(<em>D</em>)) + c(<em>A</em>)  <p>定义q(<em>i</em>,<em>j</em>)的一般形式：  <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-&nbsp; inf.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <em>j</em>&lt;1 or <em>j</em>&gt;n<br>q(<em>i</em>,<em>j</em>) = -+-&nbsp; c(<em>i</em>,<em>j</em>)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i=1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |-&nbsp; min(q(<em>i</em>-1,<em>j</em>-1),q(<em>i</em>-1,<em>j</em>),q(<em>i</em>-1,<em>j</em>+1))+c(<em>i</em>,<em>j</em>)&nbsp;&nbsp; otherwise.  <p>方程的第一行是为了保证递归可以退出（处理边界时只需调用一次递归函数）。第二行是第一阶的取值，作为计算的起点。第三行的递归是算法的重要组成部分，与例子<em>A</em>、<em>B</em>、<em>C</em>、<em>D</em>类似。从该定义我们可以直接给出计算q(<em>i</em>,<em>j</em>)的简单的递归代码。在下面的伪代码中，<em>n</em>表示棋盘的维数，C(<em>i</em>,<em>j</em>)是成本函数，min()返回一组数的最小值：  <p>function minCost(i, j)<br>&nbsp;&nbsp;&nbsp; if j &lt; 1 or j &gt; n<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return infinity<br>&nbsp;&nbsp;&nbsp; else if i = 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return c(i,j)<br>&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return min(minCost(i-1,j-1),minCost(i-1,j),minCost(i-1,j+1))+c(i,j)  <p>需要指出的是，minCost只计算路径成本，并不是最终的实际路径，二者相去不远。与Fibonacci数相似，由于花费大量时间重复计算相同的最短路径，这一方式慢的恐怖。不过，如果采用自下而上法，使用二维数组q[i,j]代替函数minCost，将使计算过程快得多。我们为什么要这样做呢？选择保存值显然比使用函数重复计算相同路径要简单的多。  <p>我们还需要知道实际路径。路径问题，我们可以通过另一个前任数组p[i,j]解决。这个数组用于描述路径，代码如下：  <p>function computeShortestPathArrays()<br>&nbsp;&nbsp;&nbsp;&nbsp; for x from 1 to n<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q[1, x] := c(1, x)<br>&nbsp;&nbsp;&nbsp;&nbsp; for y from 1 to n<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q[y, 0]&nbsp;&nbsp;&nbsp;&nbsp; := infinity<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q[y, n + 1] := infinity<br>&nbsp;&nbsp;&nbsp;&nbsp; for y from 2 to n<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for x from 1 to n<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m := min(q[y-1, x-1], q[y-1, x], q[y-1, x+1])<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q[y, x] := m + c(y, x)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if m = q[y-1, x-1]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p[y, x] := -1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if m = q[y-1, x]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p[y, x] :=&nbsp; 0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p[y, x] :=&nbsp; 1  <p>剩下的求最小值和输出就比较简单了：  <p>function computeShortestPath()<br>&nbsp;&nbsp;&nbsp;&nbsp; computeShortestPathArrays()<br>&nbsp;&nbsp;&nbsp;&nbsp; minIndex := 1<br>&nbsp;&nbsp;&nbsp;&nbsp; min := q[n, 1] <br>&nbsp;&nbsp;&nbsp;&nbsp; for i from 2 to n <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if q[n, i] &lt; min<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; minIndex := i<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; min := q[n, i]<br>&nbsp;&nbsp;&nbsp;&nbsp; printPath(n, minIndex)  <p>function printPath(y, x)<br>&nbsp;&nbsp;&nbsp;&nbsp; print(x)<br>&nbsp;&nbsp;&nbsp;&nbsp; print("&lt;-")<br>&nbsp;&nbsp;&nbsp;&nbsp; if y = 2<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print(x + p[y, x])<br>&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printPath(y-1, x + p[y, x])  <p><strong>4. 序列比对 </strong> <p><a href="http://en.wikipedia.org/wiki/Sequence_alignment" target="_blank">序列比对</a>是动态规划的一个重要应用。序列比对问题通常是使用编辑操作（替换、插入、删除一个要素等）进行序列转换。每次操作对应不同成本，目标是找到编辑序列的最低成本。  <p>可以很自然地想到使用递归解决这个问题，序列<em>A</em>到<em>B</em>的最优编辑通过以下措施之一实现：  <p>插入<em>B</em>的第一个字符，对<em>A</em>和<em>B</em>的剩余序列进行最优比对；  <p>删去<em>A</em>的第一个字符，对<em>A</em>和<em>B</em>进行最优比对；  <p>用<em>B</em>的第一个字符替换<em>A</em>的第一个字符，对<em>A</em>的剩余序列和<em>B</em>进行最优比对。  <p>局部比对可在矩阵中列表表示，单元(<em>i</em>,<em>j</em>)表示A[1..<em>i</em>]到b[1..<em>j</em>]最优比对的成本。单元(<em>i</em>,<em>j</em>)的成本计算可通过累加相邻单元的操作成本并选择最优解实现。至于序列比对的不同实现算法，参见<a href="http://en.wikipedia.org/wiki/Smith-Waterman" target="_blank">Smith-Waterman</a>和<a href="http://en.wikipedia.org/wiki/Needleman-Wunsch" target="_blank">Needleman-Wunsch</a>。  <p><strong><em>对序列比对的话题并不熟悉，更多的话也无从谈起，有熟悉的朋友倒是可以介绍一下。</em></strong>  <ul> <li><strong>应用动态规划的算法</strong> </li></ul> <p>1) 许多<a href="http://en.wikipedia.org/wiki/String_%28computer_science%29" target="_blank">字符串</a>操作算法如<a href="http://en.wikipedia.org/wiki/Longest_common_subsequence_problem" target="_blank">最长公共子列</a>、<a href="http://en.wikipedia.org/wiki/Longest_increasing_subsequence_problem" target="_blank">最长递增子列</a>、<a href="http://en.wikipedia.org/wiki/Longest_common_substring_problem" target="_blank">最长公共字串</a>； </p> <p>2) 将动态规划用于<a href="http://en.wikipedia.org/wiki/Undirected_graph" target="_blank">图</a>的树分解，可以有效解决有界<a href="http://en.wikipedia.org/wiki/Treewidth" target="_blank">树宽图</a>的<a href="http://en.wikipedia.org/wiki/Tree_decomposition" target="_blank">生成树</a>等许多与图相关的算法问题；  <p>3) 决定是否及如何可以通过某一特定<a href="http://en.wikipedia.org/wiki/Context-free_grammar" target="_blank">上下文无关文法</a>产生给定字符串的<a href="http://en.wikipedia.org/wiki/CYK_algorithm" target="_blank">Cocke-Younger-Kasami</a> (CYK)算法；  <p>4) <a href="http://en.wikipedia.org/wiki/Computer_chess" target="_blank">计算机国际象棋</a>中<a href="http://en.wikipedia.org/wiki/Transposition_table" target="_blank">转换表</a>和<a href="http://en.wikipedia.org/wiki/Refutation_table" target="_blank">驳斥表</a>的使用；  <p>5) <a href="http://en.wikipedia.org/wiki/Viterbi_algorithm" target="_blank">Viterbi算法</a>（用于<a href="http://en.wikipedia.org/wiki/Hidden_Markov_model" target="_blank">隐式马尔可夫模型</a>）；  <p>6) <a href="http://en.wikipedia.org/wiki/Earley_algorithm" target="_blank">Earley算法</a>（一类<a href="http://en.wikipedia.org/wiki/Chart_parser" target="_blank">图表分析器</a>）；  <p>7) <a href="http://en.wikipedia.org/wiki/Needleman-Wunsch_algorithm" target="_blank">Needleman-Wunsch</a>及其他<a href="http://en.wikipedia.org/wiki/Bioinformatics" target="_blank">生物信息学</a>中使用的算法，包括<a href="http://en.wikipedia.org/wiki/Sequence_alignment" target="_blank">序列比对</a>、<a href="http://en.wikipedia.org/wiki/Structural_alignment" target="_blank">结构比对</a>、<a href="http://en.wikipedia.org/wiki/RNA_structure" target="_blank">RNA结构</a>预测；  <p>8) <a href="http://en.wikipedia.org/wiki/Levenshtein_distance" target="_blank">Levenshtein距离</a>（编辑距离）；  <p>9) <a href="http://en.wikipedia.org/wiki/Floyd-Warshall_algorithm" target="_blank">弗洛伊德最短路径</a>算法；  <p>10) <a href="http://en.wikipedia.org/wiki/Chain_matrix_multiplication" target="_blank">连锁矩阵乘法</a>次序优化；  <p>11) <a href="http://en.wikipedia.org/wiki/Subset_sum_problem" target="_blank">子集求和</a>、<a href="http://en.wikipedia.org/wiki/Knapsack_problem" target="_blank">背包问题</a>和<a href="http://en.wikipedia.org/wiki/Partition_problem" target="_blank">分治问题</a>的伪多项式时间算法；  <p>12) 计算两个时间序列全局距离的<a href="http://en.wikipedia.org/wiki/Dynamic_time_warping" target="_blank">动态时间规整</a>算法；  <p>13) 关系型数据库的查询优化的<a href="http://en.wikipedia.org/wiki/Selinger" target="_blank">Selinger</a>（又名<a href="http://en.wikipedia.org/wiki/System_R" target="_blank">System R</a>）算法；  <p>14) 评价B样条曲线的<a href="http://en.wikipedia.org/wiki/De_Boor_algorithm" target="_blank">De Boor算法</a>；  <p>15) 用于解决板球运动中断问题的<a href="http://en.wikipedia.org/wiki/Duckworth-Lewis_method" target="_blank">Duckworth-Lewis</a>方法；  <p>16) 价值迭代法求解<a href="http://en.wikipedia.org/wiki/Markov_decision_process" target="_blank">马尔可夫决策过程</a>；  <p>17) 一些图形图像边缘以下的选择方法，如“磁铁”选择工具在<a href="http://en.wikipedia.org/wiki/Photoshop" target="_blank">Photoshop</a>；  <p>18) <a href="http://en.wikipedia.org/wiki/Interval_scheduling" target="_blank">间隔调度</a>；  <p>19) <a href="http://en.wikipedia.org/wiki/Word_wrap" target="_blank">自动换行</a>；  <p>20) <a href="http://en.wikipedia.org/wiki/Travelling_salesman_problem" target="_blank">巡回旅行商问题</a>（<strong><em>又称邮差问题或货担郎问题</em></strong>）；  <p>21) <a href="http://en.wikipedia.org/wiki/Segmented_least_squares" target="_blank">分段最小二乘法</a>；  <p>22) <a href="http://en.wikipedia.org/wiki/Music_Information_Retrieval" target="_blank">音乐信息检索</a>跟踪。  <p><strong><em>对于这些算法应用，大多未曾接触，甚至术语翻译的都有问题，鉴于本文主要在于介绍动态规划，所以仓促之中，未及查证。</em></strong>  <ul> <li><strong>相关</strong> </li></ul> <p>1) <a href="http://en.wikipedia.org/wiki/Bellman_equation" target="_blank">贝尔曼方程</a>  <p>2) <a href="http://en.wikipedia.org/wiki/Markov_decision_process" target="_blank">马尔可夫决策过程</a>  <p>3) <a href="http://en.wikipedia.org/wiki/Greedy_algorithm" target="_blank">贪心算法</a> </p> <ul> <li><strong>参考</strong> </li></ul> <li>Adda, Jerome, and Cooper, Russell, 2003. <em><a href="http://www.eco.utexas.edu/~cooper/dynprog/dynprog1.html">Dynamic Economics.</a></em> MIT Press. An accessible introduction to dynamic programming in economics. The link contains sample programs.  <li>Richard Bellman, 1957, <em>Dynamic Programming</em>, Princeton University Press. Dover paperback edition (2003), <a href="http://en.wikipedia.org/wiki/Special:BookSources/0486428095">ISBN 0486428095</a>.  <li>Bertsekas, D. P., 2000. <em>Dynamic Programming and Optimal Control, Vols. 1 &amp; 2</em>, 2nd ed. Athena Scientific. <a href="http://en.wikipedia.org/wiki/Special:BookSources/1886529094">ISBN 1-886529-09-4</a>.  <li><a href="http://en.wikipedia.org/wiki/Thomas_H._Cormen">Thomas H. Cormen</a>, <a href="http://en.wikipedia.org/wiki/Charles_E._Leiserson">Charles E. Leiserson</a>, <a href="http://en.wikipedia.org/wiki/Ronald_L._Rivest">Ronald L. Rivest</a>, and <a href="http://en.wikipedia.org/wiki/Clifford_Stein">Clifford Stein</a>, 2001. <em><a href="http://en.wikipedia.org/wiki/Introduction_to_Algorithms">Introduction to Algorithms</a></em>, 2nd ed. MIT Press &amp; McGraw-Hill. <a href="http://en.wikipedia.org/wiki/Special:BookSources/0262032937">ISBN 0-262-03293-7</a>. Especially pp. 323–69.  <li>Giegerich, R., Meyer, C., and Steffen, P., 2004, "<a href="http://bibiserv.techfak.uni-bielefeld.de/adp/ps/GIE-MEY-STE-2004.pdf">A Discipline of Dynamic Programming over Sequence Data,</a>" <em>Science of Computer Programming 51</em>: 215-263.  <li><a href="http://en.wikipedia.org/wiki/Nancy_Stokey">Nancy Stokey</a>, and <a href="http://en.wikipedia.org/wiki/Robert_E._Lucas">Robert E. Lucas</a>, with <a href="http://en.wikipedia.org/wiki/Edward_Prescott">Edward Prescott</a>, 1989. <em>Recursive Methods in Economic Dynamics</em>. Harvard Univ. Press.  <li>S. P. Meyn, 2007. <a href="http://decision.csl.uiuc.edu/~meyn/pages/CTCN/CTCN.html">Control Techniques for Complex Networks</a>, Cambridge University Press, 2007.  <ul> <li><strong>外部链接</strong> </li></ul> <ul> <li><a href="http://www.dyna.org/">Dyna</a>, a declarative programming language for dynamic programming algorithms  <li>Wagner, David B., 1995, "<a href="http://citeseer.ist.psu.edu/268391.html">Dynamic Programming.</a>" An introductory article on dynamic programming in <a href="http://en.wikipedia.org/wiki/Mathematica">Mathematica</a>.  <li><a href="http://www.cse.ohio-state.edu/~gurari/course/cis680/cis680Ch21.html">Ohio State University: CIS 680: class notes on dynamic programming</a>, by Eitan M. Gurari  <li><a href="http://mat.gsia.cmu.edu/classes/dynamic/dynamic.html">A Tutorial on Dynamic programming</a>  <li><a href="http://ocw.mit.edu/OcwWeb/Electrical-Engineering-and-Computer-Science/6-046JFall-2005/LectureNotes/index.htm">MIT course on algorithms</a> - Includes a video lecture on DP along with lecture notes -- See lecture 15.  <li><a href="http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Dynamic">More DP Notes</a>  <li>King, Ian, 2002 (1987), "<a href="http://www.business.auckland.ac.nz/Departments/econ/workingpapers/full/Text230.pdf">A Simple Introduction to Dynamic Programming in Macroeconomic Models.</a>" An introduction to dynamic programming as an important tool in economic theory.  <li><a href="http://www.topcoder.com/tc?module=Static&amp;d1=tutorials&amp;d2=dynProg">Dynamic Programming: from novice to advanced</a> A TopCoder.com article by Dumitru on Dynamic Programming  <li><a href="http://bibiserv.techfak.uni-bielefeld.de/adp/">Algebraic Dynamic Programming</a> - a formalized framework for dynamic programming, including an <a href="http://bibiserv.techfak.uni-bielefeld.de/dpcourse">entry-level course</a> to DP, University of Bielefeld  <li>Dreyfus, Stuart, "<a href="http://www.eng.tau.ac.il/~ami/cd/or50/1526-5463-2002-50-01-0048.pdf">Richard Bellman on the birth of Dynamic Programming.</a>"  <li><a href="http://www.avatar.se/lectures/molbioinfo2001/dynprog/dynamic.html">Dynamic programming tutorial</a>  <li><a href="http://20bits.com/2007/05/08/introduction-to-dynamic-programming/">An Introduction to Dynamic Programming</a> </li></ul> <p>_____________________________________________________________</p> <p>关于动态规划，这只是一篇译文，后面将根据实际问题具体写点动态规划的应用。</p></li><img src ="http://www.cppblog.com/Fox/aggbug/49153.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-05-07 20:43 <a href="http://www.cppblog.com/Fox/archive/2008/05/07/Dynamic_programming.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编程之美：一摞烙饼的排序（未完成）</title><link>http://www.cppblog.com/Fox/archive/2008/04/20/flapjack_sortting.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Sun, 20 Apr 2008 06:59:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/04/20/flapjack_sortting.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/47659.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/04/20/flapjack_sortting.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/47659.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/47659.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
<p>首先声明：本人没有解决掉这个问题。</p>
<p>相比第一道<a href="http://www.cppblog.com/Fox/archive/2008/04/17/control_cpu_using_curve.html" target=_blank>让CPU占用率曲线听你指挥</a>对Windows系统中CPU占有率概念的考察和对API的使用，以及第二道<a href="http://www.cppblog.com/Fox/archive/2008/04/18/chinese_chess_one_param.html" target=_blank>中国象棋将帅问题</a>对抽象建模的考察。<a href="http://book.csdn.net/bookfiles/656/10065620785.shtml" target=_blank>这道题目</a>才算是一道算法题吧？之前那两道尤其是<a href="http://www.cppblog.com/Fox/archive/2008/04/18/chinese_chess_one_param.html" target=_blank>中国象棋将帅问题</a>总有点脑筋急转弯的味道。</p>
<p>题目：<font color=#800000>星期五的晚上，一帮同事在希格玛大厦附近的&#8220;硬盘酒吧&#8221;多喝了几杯。程序员多喝了几杯之后谈什么呢？自然是算法问题。有个同事说：</font></p>
<p><font color=#800000>&#8220;我以前在餐馆打工，顾客经常点非常多的烙饼。店里的饼大小不一，我习惯在到达顾客饭桌前，把一摞饼按照大小次序摆好——小的在上面，大的在下面。由于我一只手托着盘子，只好用另一只手，一次抓住最上面的几块饼，把它们上下颠倒个个儿，反复几次之后，这摞烙饼就排好序了。</font>
<p><font color=#800000>我后来想，这实际上是个有趣的排序问题：假设有<em>n</em>块大小不一的烙饼，那最少要翻几次，才能达到最后大小有序的结果呢？</font>
<p><font color=#800000>你能否写出一个程序，对于<em>n</em>块大小不一的烙饼，输出最优化的翻饼过程呢？</font></p>
<p>排序问题是数据结构和算法中比较重要的一个了，之前在<a href="http://www.cppblog.com/Fox/archive/2008/03/20/unwisdom_or_impavidity.html" target=_blank>一篇被同事成为标题党的文章</a>中因为提到排序中关于（非）稳定排序的概念还被很多TX鄙视了一番，甚至引来人身攻击，现在想来都有些后怕。</p>
<p>这道题目一眼看上去最先让我想到的居然是那道经典的<a href="http://en.wikipedia.org/wiki/Tower_of_Hanoi" target=_blank>汉诺塔（Tower of Hanoi）</a>问题（当然，<a href="http://en.wikipedia.org/wiki/Tower_of_Hanoi" target=_blank>汉诺塔</a>不算排序问题）。</p>
<p><font color=#800000>1) 相似点★：</font></p>
<p>a. 都要不断调整位置，最终实现从小到大排好；</p>
<p>b. 都要借助中间量进行调整。</p>
<p><font color=#800000>2) 不同处★：</font></p>
<p>a. 汉诺塔有多出来的两根针，翻烙饼只有一只手，明确说明没有第三只手；</p>
<p>b. 汉诺塔一次只能移动一个，翻烙饼没限制；</p>
<p>c. 汉诺塔要保证小的始终在上面，翻烙饼没限制；</p>
<p>d. 汉诺塔移动之前就有序，所以其移动次数是固定的，算法的逻辑也固定（不管是递归还是栈操作），翻烙饼没有这个前提。</p>
<p><font color=#800000>3) 把题目用程序语言描述一下吧★：</font></p>
<p>a. Input : <em>n</em>.</p>
<p>b. Process : generate <em>n</em> random number 0-(n-1), sortting.</p>
<p>c. Output : 0, 1, ..., n-1, and move times <em>num</em>.</p>
<p><font color=#800000>4) 存储结构★★★：</font></p>
<p>我最开始想到的是：这一摞烙饼其实就是一个双链表，每翻一次相当于将头节点H与某非头节点N进行如下变换：</p>
<p>H-&gt;next = N-&gt;next</p>
<p>N-&gt;prior = H-&gt;prior = NULL</p>
<p>N-&gt;next-&gt;prior = H</p>
<p>如果使用普通的双链表，这儿就有一个很明显的问题，H和N之间的所有节点（如果有的话）的<font color=#800000>前趋prior和后继next互换</font>了，对于<em>n</em>比较大的情况，这个操作明显浪费时间啊（<font color=#800000>交换前趋prior和后继next和题目要求的翻几次似乎也没有关系吧</font>？只是我作为一个一线的Coder考虑的太具体了）。如果摒弃前趋和后继的概念，又该怎样描述呢？</p>
<p><a href="http://www.ctworld.org/chan_master/east010.htm" target=_blank>唐朝禅宗大师青原行思</a>曾说：<font color=#800000><strong>参禅之初，看山是山，看水是水；禅有悟时，看山不是山，看水不是水；禅中彻悟，看山仍然山，看水仍然是水</strong></font>。</p>
<p>俗：日，扯那么多，什么意思？
<p>师：前趋不是前趋，后继不是后继。
<p>俗：日，前趋不是前趋，难道是后继吗？
<p>师：然也。
<p><font color=#800000><strong>Fox：O, my God！整点实际的吧！翻转一次之后，前趋视为后继，后继视为前趋，第奇数次翻转的前趋是后继，第偶数次翻转的后继是前趋。</strong></font>
<p>整个链表的形态如下：</p>
<p>H:Head, F:First, G:F's next, B:C's prior, C:Change, D, C's next, L:Last.</p>
<p>H&lt;==&gt;F&lt;==&gt;G&lt;=...=&gt;B&lt;==&gt;C&lt;==&gt;D&lt;=...=&gt;L</p>
<p>F与C交换的操作如下（Word、PS画图），n表示next，p表示prior：</p>
<p align=center><img src="http://lh3.ggpht.com/yulefox/SAnuzSRgEtI/AAAAAAAAAMg/EFmsyGW5lWw/s800/flapjack_before_cross.jpg"> </p>
<p align=center><img src="http://lh3.ggpht.com/yulefox/SAnuySRgEsI/AAAAAAAAAMY/ncke8G_JIXo/s800/flapjack_after_cross.jpg%22" src_cetemp='http://lh3.ggpht.com/yulefox/SAnuySRgEsI/AAAAAAAAAMY/ncke8G_JIXo/s800/flapjack_after_cross.jpg"'> </p>
<p>这里只需要修改<font color=#800000>F、D节点的prior，H、C节点的next</font>，其他节点不变。</p>
<p>后面想了一下，这种方式很难在不添加flag或者对换n、p的情况下正常操作，没有找到好的方法<span style="FONT-FAMILY: wingdings">L</span>，<font color=#800000><strong>如果你有好的方法不妨告诉我</strong></font>。</p>
<p>最后只好作罢，何苦呢？直接使用数组就完了嘛<span style="FONT-FAMILY: wingdings">J</span>！既然是数组，除了翻转移动麻烦一点，理解和操作还是很容易的。</p>
<p>果然不是搞数学、算法出身的，一上来考虑的就是如何存储^.^''''，而不是算法本身。</p>
<p><strong><font color=#800000>更可笑的是，扯了半天，最后居然还是用数组</font></strong>！</p>
<p><font color=#800000>5) 算法分析★★★★★：</font></p>
<p><strong><font color=#800000>冒泡排序思想：</font></strong></p>
<p>最关键的是要抽象出<strong>随机数列特征</strong>（含当前和移动后数列特征的抽象），并尽量使每一次翻转<strong>有效</strong>（所谓<strong>有效</strong>，即尽量保证每一次操作都向最后的有序靠近而非背离 ）。</p>
<p>师：要使大头在后，应使大头在后。</p>
<p>俗：日，这是什么狗屁逻辑？</p>
<p>师：因果。在前既是在后。</p>
<p>俗：USA, CNN（操你娘）。</p>
<p>师：翻转。既不在前，也不在后，使之在前，使之在后。</p>
<p>俗：日，什么东西？既不在前，也不在后，不前不后，难道在中间啊？</p>
<p>师：然也。</p>
<p><strong><font color=#800000>Fox：O, my God！整点实际的吧！整个过程分为n轮，在第i(i=0, 1, ..., n-1)轮：</font></strong></p>
<p>a. 找到大头<em><strong>n-i</strong></em>，是否有序？是，转g；</p>
<p>b. 是否大头在后？是，转f；</p>
<p>c. 是否大头在前？是，转e；</p>
<p>d. 将队头（第一个元素）与大头<strong><em>n-i</em></strong>对调（别忘了是翻转，中间元素也变序了），++<strong><em>times</em></strong>；</p>
<p>e. 将队头<strong><em>n-i</em></strong>与第n-i个元素对调，++<strong><em>times</em></strong>；</p>
<p>f. ++<strong><em>i</em></strong>，转a；</p>
<p>g. 输出序列（0, 1, ..., n）和翻转次数<strong><em>times</em></strong>；OVER:D。</p>
<p><strong><font color=#800000>快速排序思想：</font></strong></p>
<p>在最开始的时候，我就想到使用快速排序的思想，先使整个数列局部有序，最后调整使全部有序。<strong><font color=#800000>悲哀的是，在我考虑 4 3 1 2这个数列的时候，我断定还要通过上面的方式重新像冒泡排序一样重新来过，立即放弃想法，于是给了上面的思路，而且坚定的认为这个方法已经很好</font></strong>。结果，下午GR告诉我他的反例：<font color=#800000><strong>4 3 1 2 --&gt; 2 1 3 4|--&gt; 1 2| 3 4</strong></font>，&#8220;|&#8221;表示从该处翻转。</p>
<p>我必须承认，这才是好的方法，我过分拘泥于不去改动已经有序的部分。然而，这家伙只知道反驳我，却无法给出算法。</p>
<p>我只好自己重新考虑局部有序之后的问题。</p>
<p>十分钟后，我有了如下的答案（<strong><font color=#800000>目前我能想到的最佳答案</font></strong>），但不得不承认，<strong><font color=#800000>表述算法比给出一种情况对应的解要麻烦的多的多的多</font></strong>，假定A、B满足<strong><font color=#800000>A==B-1</font></strong>，即A、B为相邻数列（为简单记，元素和数列统称数列）。则A、B的组合类型有8种：<strong>B(O)A(O)、B(C)A(O)、B(O)A(C)、B(C)A(C)、A(C)B(O)、A(O)B(O)、A(C)B(C)、A(O)B(C)</strong>，O表示正向（obverse）C表示逆向（reverse），以1 2 3 4为例：</p>
<p><font color=#800000><font color=#000000><strike>B(O)A(O)：3 4 1 2&lt;2&gt;</strike>、</font>B(C)A(O)：4 3 1 2&lt;4&gt;<font color=#000000>、</font><strong>B(O)A(C)：3 4 2 1</strong>&lt;5&gt;</font>、B(C)A(C)：4 3 2 1&lt;7&gt;；</p>
<p><font color=#800000><font color=#000000><strike>A(C)B(C)：2 1 4 3&lt;1&gt;</strike>、</font>A</font><font color=#800000>(O)B(C)：1 2 4 3&lt;3&gt;<font color=#000000>、</font><strong>A(C)B(O)：2 1 3 4</strong>&lt;6&gt;</font><font color=#000000>、A(O)B(O)：1 2 3 4&lt;8&gt;。</font></p>
<p>对应操作规则如下：</p>
<p><strike>a. 0x0101: B(O)A(O) --&gt; B(C)A(O)； 3</strike></p>
<p>b. 0x0001: B(C)A(O) --&gt; A(C)B(O)； 2</p>
<p><font color=#800000>c. 0x0101: B(O)A(C) --&gt; <strong>B(C)A(C)</strong>；1</font></p>
<p>d. 0x0000: B(C)A(C)：<strong>如果当前只剩A、B两个子列</strong>，则翻转一次成<strong><font color=#800000>A(O)B(O)1 2 3 4为最终结果</font></strong>，否则，认为<strong><font color=#800000>B(C)A(C)</font></strong>可以<strong>作为一个逆序有序数列考虑</strong>，暂时无需翻转；</p>
<p><strike>e. 0x1010: A(C)B(C) --&gt; A(O)B(C)； 3</strike></p>
<p>f. 0x1110: A(O)B(C) --&gt; B(O)A(C)；&nbsp; 2</p>
<p><font color=#800000>g. 0x1011: A(C)B(O) --&gt; <strong>A(O)B(O)</strong>；1</font></p>
<p>h. 0x1111: A(O)B(O)：A、B可以<strong>作为一个有序数列考虑</strong>，<strong>如果当前只有A、B两个子列</strong>，则正序序列<strong><font color=#800000>A(O)B(O)1 2 3 4为最终结果</font></strong>。</p>
<p>上面规则的制定其实是<strong>反向导出</strong>的，遵循的原则是，正序有序的<strong><font color=#800000>A(O)B(O)</font></strong>和逆序有序的<strong><font color=#800000>B(C)A(C)</font></strong>可以看作一个序列，A(C)B(O)、B(O)A(C)可一步达到，B(C)A(O)、A(O)B(C)可两步达到，B(O)A(O)、A(C)B(C)可三步达到。即对于4个元素，<strong>最坏的的A(C)B(C)需要4步</strong>（对应于上面的<font color=#800000>冒泡法却只需要3步</font><span style="FONT-FAMILY: wingdings">L</span>）。而且当元素比较多的时候，记住1、2个有序子列是可行的，但对于完全无序的数列，分析出所有有序子列，既不现实，也无必要。</p>
<p>修改规则如下：<font color=#800000>当<strong>队头无序</strong>&amp;&amp;<strong>相邻数列有序</strong>||<strong>队头有序</strong>，翻转队头；否则，将队头连同该元素一同翻转</font>。</p>
<p>由此可见，这算法还要改进：</p>
<p>a. 判断<strong><em>Array</em>[0]</strong>是否正序连续（连续个数<strong><em>nNum1</em></strong>），如果<em><strong>nNum1</strong></em>==<strong><em>n</em></strong>，转i，如果<strong><em>nNum1</em></strong>!=1，转c；</p>
<p>b. 判断<strong><em>Array</em>[0]</strong>是否逆序连续（连续个数<strong><em>nNum1</em></strong>），如果<em><strong>nNum1</strong></em>==<strong><em>n</em></strong>，翻转<strong><em>Array</em></strong>，转f；</p>
<p>c. 从下标<strong><em>nNum1</em></strong>开始查找<strong><em>Array</em>[0]</strong>+1（<em><strong>bObserve</strong></em> = true）和<strong><em>Array</em>[0]-</strong>1（<em><strong>bObserve</strong></em> = false）的下标<strong><em>nStart2</em></strong>，如果<strong><em>nNum1</em></strong>==<strong><em>nStart2</em></strong>，<strong><em>bOrder1</em></strong>==true，转e，如果<strong><em>nNum1</em></strong>!=1，置<strong><em>nEnd2</em></strong>=<strong><em>nStart2</em></strong>；</p>
<p>d. 判断( <em><strong>bObserve</strong></em> == true&amp;&amp;<strong><em>Array</em>[nStart2]</strong>+1<strong>==<em>Array</em>[nStart2+1] </strong>) || ( <em><strong>bObserve</strong></em> == false&amp;&amp;<strong><em>Array</em>[nStart2]==<em>Array</em>[nStart2+1]</strong>+1 )，true则置<strong><em>nEnd2</em></strong>=<strong><em>nStart2</em></strong>，false则置<strong><em>nEnd2</em></strong>=<strong><em>nStart2</em></strong>+1；</p>
<p>e. 翻转<strong>Array[0]</strong> to <strong>Array[nEnd2]</strong>，转a；</p>
<p>f. 输出<strong>Array</strong>及<strong>times</strong>。</p>
<p>这样来看，改进后的算法竟<strong>简单</strong>了许多！</p>
<p>不幸的是：按上面给出的算法翻转合并1 3 5 6 4 8 7 9 2 0：</p>
<p><font color=#800000>1 3 5 6 4 8 7 9| </font><font color=#008000>2|</font> 0</p>
<p><font color=#800000>2 9 7 8 4 6 5|</font> <font color=#008000>3|</font> 1 0</p>
<p><font color=#800000>3 5 6|</font> <font color=#008000>4|</font> 8 7 9 2 1 0</p>
<p><font color=#800000>4 6|</font> <font color=#008000>5|</font> 3 8 7 9 2 1 0</p>
<p><font color=#800000><strong>5 6</strong>|</font> 4 3 8 7 9 2 1 0</p>
<p><font color=#800000>6 5 4 3 8|</font> <font color=#008000>7|</font> 9 2 1 0</p>
<p><font color=#800000>7 8 3 4 5|</font> <font color=#008000>6|</font> 9 2 1 0</p>
<p>进入死循环了&#8230;&#8230;</p>
<p>很明显应该是下面这个样子：</p>
<p><font color=#800000>1 3 5 6 4 8 7 9 2|</font> 0</p>
<p><font color=#800000>9 8 7 4 6 5|</font> 3 1 2 0</p>
<p><font color=#800000>5 6 4|</font> 7 8 9 3 1 2 0</p>
<p><font color=#800000>6 5 4 7|</font> 8 9 3 1 2 0</p>
<p><font color=#800000>4 5 6 7 8 9 3|</font> 1 2 0</p>
<p><font color=#800000>3 4 5 6 7 8 9 1 2|</font> 0</p>
<p><font color=#800000>1 9 8 7 6 5 4 3 2|</font> 0</p>
<p><font color=#800000>2 3 4 5 6 7 8 9 1|</font> 0</p>
<p><font color=#800000>9 8 7 6 5 4 3 2 1 0|</font></p>
<p><font color=#008000><strong>0 1 2 3 4 5 6 7 8 9</strong></font></p>
<p>执行9次翻转。算法如何得到呢？</p>
<p>a. 确定最小无序完整子集<strong><em>Sn</em></strong>（<strong><em>Sn</em></strong>中含<strong><em>n</em></strong>&gt;1个连续数）；</p>
<p>b. 将<strong><em>Sn</em></strong>最前面的有序子集<strong><em>So</em></strong>（<strong><em>o</em></strong>&gt;1）加以考虑，一个子集？两个子集？</p>
<p>______________________________________________________________________________</p>
<p><strong><font color=#800000>O, my God!</font></strong></p>
<p>这个问题，从前天晚上到现在，思考、分析、抽象了至少有15个小时以上了：</p>
<p>a. Apr.18th-19th: 23:00 - 01:30</p>
<p>b. Apr.19th: 11:00 - 13:00</p>
<p>c. Apr.19th-20th: 22:00 - 05:30</p>
<p>d. Apr.20th: 11:00 - 15:00</p>
<p>结果是，到现在无法给出一个最优的翻转算法。一个周末都花在这上面了，<strong><font color=#800000>准备放弃</font></strong><span style="FONT-FAMILY: wingdings">L</span>。</p>
<p><a href="http://pekingone.blog.sohu.com/" target=_blank>LP</a>催着我让我回学校，是该回去了！</p><img src ="http://www.cppblog.com/Fox/aggbug/47659.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-04-20 14:59 <a href="http://www.cppblog.com/Fox/archive/2008/04/20/flapjack_sortting.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编程之美：中国象棋将帅问题</title><link>http://www.cppblog.com/Fox/archive/2008/04/18/chinese_chess_one_param.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Thu, 17 Apr 2008 16:26:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/04/18/chinese_chess_one_param.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/47457.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/04/18/chinese_chess_one_param.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/47457.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/47457.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
<p>晚上没有加班，打游戏打到9点过，后面就又看了一道《<a href="http://www.china-pub.com/38070" target=_blank>编程之美</a>》的题目《<a href="http://book.csdn.net/bookfiles/656/10065620784.shtml" target=_blank>中国象棋将帅问题</a>》。</p>
<p><font color=#800000>题目：下过中国象棋的朋友都知道，双方的&#8220;将&#8221;和&#8220;帅&#8221;相隔遥远，并且它们不能照面。在象棋残局中，许多高手能利用这一规则走出精妙的杀招。假设棋盘上只有&#8220;将&#8221;和&#8220;帅&#8221;二子（如图1-3所示）（为了下面叙述方便，我们约定用<em>A</em>表示&#8220;将&#8221;，<em>B</em>表示&#8220;帅&#8221;）：</font></p>
<p align=center><font color=#800000><img height=243 alt=1-3副本 src="http://book.csdn.net/BookFiles/656/img/image003.jpg" width=224 border=0></font></p>
<p><font color=#800000><em>A</em>、<em>B</em>二子被限制在己方3&#215;3的格子里运动。例如,在如上的表格里，<em>A</em>被正方形{<em>d</em><sub>10</sub>, <em>f</em><sub>10</sub>, <em>d</em><sub>8</sub>, <em>f</em><sub>8</sub>}包围，而<em>B</em>被正方形{<em>d</em><sub>3</sub>, <em>f</em><sub>3</sub>, <em>d</em><sub>1</sub>, <em>f</em><sub>1</sub>}包围。每一步，<em>A</em>、<em>B</em>分别可以横向或纵向移动一格，但不能沿对角线移动。另外，<em>A</em>不能面对<em>B</em>，也就是说，<em>A</em>和<em>B</em>不能处于同一纵向直线上（比如<em>A</em>在<em>d</em><sub>10</sub>的位置，那么<em>B</em>就不能在<em>d</em><sub>1</sub>、<em>d</em><sub>2</sub>以及<em>d</em><sub>3</sub>）。</font>
<p><font color=#800000>请写出一个程序，输出<em>A</em>、<em>B</em>所有合法位置。要求在代码中只能使用一个变量。</font>
<p><font color=#800000></font>
<p>在纸上画了半天，Soft从台湾给带的长寿都让我抽完了，总算对得起这会儿工夫&#8230;&#8230;</p>
<p>我的思路大致如下：</p>
<p>1) 只能使用一个变量nNum ==&gt; 只能使用一个循环，nNum只能用来表示A、B位置的组合，nNum最大为9&#215;9-1=80；</p>
<p>2) 如何用nNum表示一个A、B位置的组合？</p>
<p>下图表示<font color=#800000>A（红色）</font>、<font color=#000080>B（蓝色）</font>所在位置：</p>
<table cellSpacing=0 cellPadding=20 width=102 align=center border=1>
    <tbody>
        <tr>
            <td vAlign=top width=51><font color=#800000>6</font></td>
            <td vAlign=top width=51><font color=#800000>7</font></td>
            <td vAlign=top width=51><font color=#800000>8</font></td>
        </tr>
        <tr>
            <td vAlign=top width=51><font color=#800000>3</font></td>
            <td vAlign=top width=51><font color=#800000>4</font></td>
            <td vAlign=top width=51><font color=#800000>5</font></td>
        </tr>
        <tr>
            <td vAlign=top width=51><font color=#800000>0</font></td>
            <td vAlign=top width=51><font color=#800000>1</font></td>
            <td vAlign=top width=51><font color=#800000>2</font></td>
        </tr>
        <tr>
            <td vAlign=top width=51><font color=#000080>6</font></td>
            <td vAlign=top width=51><font color=#000080>7</font></td>
            <td vAlign=top width=51><font color=#000080>8</font></td>
        </tr>
        <tr>
            <td vAlign=top width=51><font color=#000080>3</font></td>
            <td vAlign=top width=51><font color=#000080>4</font></td>
            <td vAlign=top width=51><font color=#000080>5</font></td>
        </tr>
        <tr>
            <td vAlign=top width=51><font color=#000080>0</font></td>
            <td vAlign=top width=51><font color=#000080>1</font></td>
            <td vAlign=top width=51><font color=#000080>2</font></td>
        </tr>
    </tbody>
</table>
<p>以<font color=#800000>nNum%9表示A的位置</font>，<font color=#000080>nNum/9表示B的位置</font>，如nNum==15，<font color=#800000>A==6</font>，<font color=#000080>B==1</font>。</p>
<p>3) 如何确定A、B位置的合法性？</p>
<p>规则都指定了，合法性的确定也就很简单了：A%3 != B%3。</p>
<p>OK，剩下的输出就很简单了，为了好看一点，这里希望直接按题目给的图表示出A、B的位置，如：&#8220;<font color=#800000>A:d10</font>, <font color=#000080>B:e3</font>&#8221;，还有颜色:D。</p>
<p>A的行号：A/3+8；</p>
<p>A的列号：A%3+d；</p>
<p>B的行号：B/3+1；</p>
<p>B的列号：B%3+d；</p>
<p>代码如下（注释掉的部分只是为了输出更&#8220;漂亮&#8221;一点）：<br></p>
<p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: courier new; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">#include&nbsp;&lt;windows.h&gt;<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">HANDLE&nbsp;hStdout;<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">CONSOLE_SCREEN_BUFFER_INFO&nbsp;csbiInfo;<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">WORD&nbsp;wOldColorAttrs;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;_tmain(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;_TCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">hStdout&nbsp;=&nbsp;GetStdHandle(STD_OUTPUT_HANDLE);<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">GetConsoleScreenBufferInfo(hStdout,&nbsp;&amp;csbiInfo);<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">wOldColorAttrs&nbsp;=&nbsp;csbiInfo.wAttributes;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;nNum&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">81</span><span style="COLOR: #000000">;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;nNum表示所有位置（含非法），故nNum&nbsp;=&nbsp;3&nbsp;*&nbsp;3&nbsp;*&nbsp;3&nbsp;*&nbsp;3</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(&nbsp;nNum</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">&nbsp;)<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;nNum</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">9</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;nNum</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">9</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">&nbsp;)<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">SetConsoleTextAttribute(hStdout,&nbsp;FOREGROUND_RED&nbsp;|&nbsp;FOREGROUND_INTENSITY);</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">A:%x%02d&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;nNum</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">9</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">0xd</span><span style="COLOR: #000000">,&nbsp;nNum</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">9</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">SetConsoleTextAttribute(hStdout,&nbsp;FOREGROUND_BLUE&nbsp;|&nbsp;FOREGROUND_INTENSITY);</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">B:%x%02d&nbsp;&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;nNum</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">9</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">0xd</span><span style="COLOR: #000000">,&nbsp;nNum</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">9</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">(nNum</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">9</span><span style="COLOR: #000000">)&nbsp;)<br></span><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">26</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;};<br></span><span style="COLOR: #008080">27</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">28</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">SetConsoleTextAttribute(hStdout,&nbsp;wOldColorAttrs);</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">29</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">30</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<p>输出：</p>
<p align=center><a href=http://picasaweb.google.com/yulefox/Blog/photo#5190249214067771810 target=_blank><img src="http://lh3.ggpht.com/yulefox/SAd4KTxCiaI/AAAAAAAAAK8/WyHyft6R-QY/s800/one_param_output.JPG">点击查看更清晰原图:D</a> </p>
<p>PS: 刚写完，没有来得及总结更多，急着向<a href="http://pekingone.blog.sohu.com/" target=_blank>LP</a>炫耀。但上面的思路应该比较清晰了，也不管书上的答案了，反正我感觉我这点代码效率应该也不会低到哪儿吧:-)？</p><img src ="http://www.cppblog.com/Fox/aggbug/47457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-04-18 00:26 <a href="http://www.cppblog.com/Fox/archive/2008/04/18/chinese_chess_one_param.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编程之美：让CPU占用率曲线听你指挥</title><link>http://www.cppblog.com/Fox/archive/2008/04/17/control_cpu_using_curve.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Wed, 16 Apr 2008 16:20:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/04/17/control_cpu_using_curve.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/47343.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/04/17/control_cpu_using_curve.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/47343.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/47343.html</trackback:ping><description><![CDATA[<p>Author: Fox</p> <p>前两天在买《<a href="http://en.wikipedia.org/wiki/The_Art_of_Computer_Programming" target="_blank">计算机程序设计艺术</a>》中文版的时候，偶然发现《<a href="http://www.china-pub.com/38070" target="_blank">编程之美</a>》这本书，当时翻了一下，看到“<font color="#800000">让CPU占用率曲线听你指挥</font>”这样的题目确实让人为之一动。写一段代码，可以让CPU占有率曲线画出平滑的正弦曲线，有点意思:-)。</p> <p>当然，最后没有买这本书，虽然我可以肯定这是本好书。</p> <p>我从<a href="http://book.csdn.net/" target="_blank">CSDN读书</a>上找到几节，闲来读一读。今天来讨论一下《<a href="http://book.csdn.net/bookfiles/656/10065620783.shtml" target="_blank">让CPU占用率曲线听你指挥</a>》。</p> <p><font color="#800000">题目：写一个程序，让用户来决定Windows任务管理器（Task Manager）的CPU占用率。程序越精简越好，计算机语言不限。例如，可以实现下面三种情况：</font></p> <p><font color="#800000">1.&nbsp;&nbsp;&nbsp; CPU的占用率固定在50%，为一条直线；</font> <p><font color="#800000">2.&nbsp;&nbsp;&nbsp; CPU的占用率为一条直线，但是具体占用率由命令行参数决定（参数范围1~ 100）；</font> <p><font color="#800000">3.&nbsp;&nbsp;&nbsp; CPU的占用率状态是一个正弦曲线。</font> <p>在讨论具体实现之前，一个非常重要的问题是：<font color="#800000">什么是CPU占用率</font>？</p> <p>《<a href="http://www.china-pub.com/38070" target="_blank">编程之美</a>》写道：“<font color="#800000">在任务管理器的一个刷新周期内，CPU忙（执行应用程序）的时间和刷新周期总时间的比率，就是CPU的占用率，也就是说，任务管理器中显示的是每个刷新周期内CPU占用率的统计平均值。</font>”</p> <p>打开“Windows 任务管理器”，“性能”中有“CPU使用记录”一项，给出的就是CPU占有率曲线。</p> <p>至于一个刷新周期到底是多长，<a href="http://book.csdn.net/bookfiles/656/10065620783.shtml" target="_blank">书中</a>似乎没有明确给出，只是说“大约是1秒钟更新一次”，我打开Windows自带的时钟，也感觉大约是1秒钟。</p> <p>另外的常识是：</p> <p>单核环境下，空死循环会导致100%的CPU占有率。双核环境下，CPU总占有率大约为50%，四核会不会是25%左右呢？（我没有四核，只能猜测了，估计各核间切换也会耗掉点时间，因为我的双核环境并没有出现一核100%，另一核空闲的情况）。</p> <p>当CPU整个刷新周期（绝大多数时间）空闲时，CPU占有率趋于0。</p> <p><a href="http://book.csdn.net/bookfiles/656/10065620783.shtml" target="_blank">书中</a>给出的正弦实现如下：</p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; font-family: courier new; background-color: #eeeeee"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">#include </span><span style="color: #000000">"</span><span style="color: #000000">Windows.h</span><span style="color: #000000">"</span><span style="color: #000000"><br></span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">#include </span><span style="color: #000000">"</span><span style="color: #000000">stdlib.h</span><span style="color: #000000">"</span><span style="color: #000000"><br></span><span style="color: #008080">3</span>&nbsp;<span style="color: #000000">#include </span><span style="color: #000000">"</span><span style="color: #000000">math.h</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;<br></span><span style="color: #008080">4</span>&nbsp;<span style="color: #000000"><br></span><span style="color: #008080">5</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">double</span><span style="color: #000000"> SPLIT </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0.01</span><span style="color: #000000">;<br></span><span style="color: #008080">6</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000"> COUNT </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">200</span><span style="color: #000000">;<br></span><span style="color: #008080">7</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">double</span><span style="color: #000000"> PI </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">3.14159265</span><span style="color: #000000">;<br></span><span style="color: #008080">8</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000"> INTERVAL </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">300</span><span style="color: #000000">; <br></span><span style="color: #008080">9</span>&nbsp;<span style="color: #000000"><br></span><span style="color: #008080">10</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">int</span><span style="color: #000000"> _tmain(</span><span style="color: #0000ff">int</span><span style="color: #000000"> argc, _TCHAR</span><span style="color: #000000">*</span><span style="color: #000000"> argv[])<br></span><span style="color: #008080">11</span>&nbsp;<span style="color: #000000">{<br></span><span style="color: #008080">12</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; DWORD busySpan[COUNT];&nbsp; </span><span style="color: #008000">//</span><span style="color: #008000">array of busy times</span><span style="color: #008000"><br></span><span style="color: #008080">13</span>&nbsp;<span style="color: #008000"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp; DWORD idleSpan[COUNT];&nbsp; </span><span style="color: #008000">//</span><span style="color: #008000">array of idle times</span><span style="color: #008000"><br></span><span style="color: #008080">14</span>&nbsp;<span style="color: #008000"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">int</span><span style="color: #000000"> half </span><span style="color: #000000">=</span><span style="color: #000000"> INTERVAL </span><span style="color: #000000">/</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">2</span><span style="color: #000000">;<br></span><span style="color: #008080">15</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">double</span><span style="color: #000000"> radian </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0.0</span><span style="color: #000000">;<br></span><span style="color: #008080">16</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">for</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000"> i </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">; i </span><span style="color: #000000">&lt;</span><span style="color: #000000"> COUNT; i</span><span style="color: #000000">++</span><span style="color: #000000">)<br></span><span style="color: #008080">17</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; {<br></span><span style="color: #008080">18</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; busySpan[i] </span><span style="color: #000000">=</span><span style="color: #000000"> (DWORD)(half </span><span style="color: #000000">+</span><span style="color: #000000"> (sin(PI </span><span style="color: #000000">*</span><span style="color: #000000"> radian) </span><span style="color: #000000">*</span><span style="color: #000000"> half));<br></span><span style="color: #008080">19</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; idleSpan[i] </span><span style="color: #000000">=</span><span style="color: #000000"> INTERVAL </span><span style="color: #000000">-</span><span style="color: #000000"> busySpan[i];<br></span><span style="color: #008080">20</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; radian </span><span style="color: #000000">+=</span><span style="color: #000000"> SPLIT;<br></span><span style="color: #008080">21</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; }<br></span><span style="color: #008080">22</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; DWORD startTime </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br></span><span style="color: #008080">23</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">int</span><span style="color: #000000"> j </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br></span><span style="color: #008080">24</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">while</span><span style="color: #000000"> (</span><span style="color: #0000ff">true</span><span style="color: #000000">)<br></span><span style="color: #008080">25</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; {<br></span><span style="color: #008080">26</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; j </span><span style="color: #000000">=</span><span style="color: #000000"> j </span><span style="color: #000000">%</span><span style="color: #000000"> COUNT;<br></span><span style="color: #008080">27</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; startTime </span><span style="color: #000000">=</span><span style="color: #000000"> GetTickCount();<br></span><span style="color: #008080">28</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">while</span><span style="color: #000000"> ((GetTickCount() </span><span style="color: #000000">-</span><span style="color: #000000"> startTime) </span><span style="color: #000000">&lt;=</span><span style="color: #000000"> busySpan[j]) ;<br></span><span style="color: #008080">29</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sleep(idleSpan[j]);<br></span><span style="color: #008080">30</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; j</span><span style="color: #000000">++</span><span style="color: #000000">;<br></span><span style="color: #008080">31</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; }<br></span><span style="color: #008080">32</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br></span><span style="color: #008080">33</span>&nbsp;<span style="color: #000000">}</span></div> <p><br>在单核环境（P4 2.40）下，其表现还是不错的：</p> <p align="center"><a href="http://picasaweb.google.com/yulefox/Blog/photo#5189783656792754530"><img src="http://lh5.ggpht.com/yulefox/SAXQvTxCiWI/AAAAAAAAAI4/pG3RTW7cK48/s144/cpu_curve_sin.jpg">点击查看大图</a></p> <p>在双核环境（Core2 E4500）下，就有点<strike>差强人意</strike>不尽人意了：</p> <p align="center"><a href="http://picasaweb.google.com/yulefox/Blog/photo#5189783669677656434"><img src="http://lh4.ggpht.com/yulefox/SAXQwDxCiXI/AAAAAAAAAJA/uAcw6fG2HsA/s144/cpu_curve_sin_core2.jpg">点击查看大图</a></p> <p>不过，总还能看出是正弦曲线。</p> <p>上面两图的问题：</p> <p>1) 单核时曲线不够平滑，是由于QQ等程序占用CPU所致；</p> <p>2) 双核时曲线更加抖动，我的理解是除其他程序影响外，由于线程没有固定运行在一个CPU上导致的，后面看到<a href="http://book.csdn.net/bookfiles/656/10065620783.shtml" target="_blank">书上</a>提到<font color="#800000">线程迁移</font>，个人感觉这个叫法欠妥啊，总觉得<font color="#800000">线程迁移</font>令人费解。</p> <p>可以立即想到的是：<font color="#800000">让进程在指定处理器上运行（处理器亲缘关系）</font>，由Windows提供了两个API可以做到这一点：<strong>GetCurrentProcess</strong>和<strong>SetProcessAffinityMask</strong>的。</p> <p>修改之后的代码如下：</p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; font-family: courier new; background-color: #eeeeee"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">#include </span><span style="color: #000000">"</span><span style="color: #000000">Windows.h</span><span style="color: #000000">"</span><span style="color: #000000"><br></span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">#include </span><span style="color: #000000">"</span><span style="color: #000000">stdlib.h</span><span style="color: #000000">"</span><span style="color: #000000"><br></span><span style="color: #008080">3</span>&nbsp;<span style="color: #000000">#include </span><span style="color: #000000">"</span><span style="color: #000000">math.h</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;<br></span><span style="color: #008080">4</span>&nbsp;<span style="color: #000000"><br></span><span style="color: #008080">5</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">double</span><span style="color: #000000"> SPLIT </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0.01</span><span style="color: #000000">;<br></span><span style="color: #008080">6</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000"> COUNT </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">200</span><span style="color: #000000">;<br></span><span style="color: #008080">7</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">double</span><span style="color: #000000"> PI </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">3.14159265</span><span style="color: #000000">;<br></span><span style="color: #008080">8</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000"> INTERVAL </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">300</span><span style="color: #000000">; <br></span><span style="color: #008080">9</span>&nbsp;<span style="color: #000000"><br></span><span style="color: #008080">10</span>&nbsp;<span style="color: #000000"></span><span style="color: #0000ff">int</span><span style="color: #000000"> _tmain(</span><span style="color: #0000ff">int</span><span style="color: #000000"> argc, _TCHAR</span><span style="color: #000000">*</span><span style="color: #000000"> argv[])<br></span><span style="color: #008080">11</span>&nbsp;<span style="color: #000000">{<br></span><span style="color: #008080">12</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp; <span style="color: red">SetProcessAffinityMask</span>(<br></span><span style="color: #008080">13</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: red">GetCurrentProcess</span>(),<br></span><span style="color: #008080">14</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: red">0x00000001&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #008000">//cpu mask</span></span><span style="color: #000000"><br></span><span style="color: #008080">15</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ); <br></span><span style="color: #008080">16</span>&nbsp;<span style="color: #000000"><br></span><span style="color: #008080">17</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; DWORD busySpan[COUNT];&nbsp; </span><span style="color: #008000">//</span><span style="color: #008000">array of busy times</span><span style="color: #008000"><br></span><span style="color: #008080">18</span>&nbsp;<span style="color: #008000"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp; DWORD idleSpan[COUNT];&nbsp; </span><span style="color: #008000">//</span><span style="color: #008000">array of idle times</span><span style="color: #008000"><br></span><span style="color: #008080">19</span>&nbsp;<span style="color: #008000"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">int</span><span style="color: #000000"> half </span><span style="color: #000000">=</span><span style="color: #000000"> INTERVAL </span><span style="color: #000000">/</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">2</span><span style="color: #000000">;<br></span><span style="color: #008080">20</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">double</span><span style="color: #000000"> radian </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0.0</span><span style="color: #000000">;<br></span><span style="color: #008080">21</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">for</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000"> i </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">; i </span><span style="color: #000000">&lt;</span><span style="color: #000000"> COUNT; i</span><span style="color: #000000">++</span><span style="color: #000000">)<br></span><span style="color: #008080">22</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; {<br></span><span style="color: #008080">23</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; busySpan[i] </span><span style="color: #000000">=</span><span style="color: #000000"> (DWORD)(half </span><span style="color: #000000">+</span><span style="color: #000000"> (sin(PI </span><span style="color: #000000">*</span><span style="color: #000000"> radian) </span><span style="color: #000000">*</span><span style="color: #000000"> half));<br></span><span style="color: #008080">24</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; idleSpan[i] </span><span style="color: #000000">=</span><span style="color: #000000"> INTERVAL </span><span style="color: #000000">-</span><span style="color: #000000"> busySpan[i];<br></span><span style="color: #008080">25</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; radian </span><span style="color: #000000">+=</span><span style="color: #000000"> SPLIT;<br></span><span style="color: #008080">26</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; }<br></span><span style="color: #008080">27</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; DWORD startTime </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br></span><span style="color: #008080">28</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">int</span><span style="color: #000000"> j </span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br></span><span style="color: #008080">29</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">while</span><span style="color: #000000"> (</span><span style="color: #0000ff">true</span><span style="color: #000000">)<br></span><span style="color: #008080">30</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; {<br></span><span style="color: #008080">31</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; j </span><span style="color: #000000">=</span><span style="color: #000000"> j </span><span style="color: #000000">%</span><span style="color: #000000"> COUNT;<br></span><span style="color: #008080">32</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; startTime </span><span style="color: #000000">=</span><span style="color: #000000"> GetTickCount();<br></span><span style="color: #008080">33</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">while</span><span style="color: #000000"> ((GetTickCount() </span><span style="color: #000000">-</span><span style="color: #000000"> startTime) </span><span style="color: #000000">&lt;=</span><span style="color: #000000"> busySpan[j]) ;<br></span><span style="color: #008080">34</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sleep(idleSpan[j]);<br></span><span style="color: #008080">35</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; j</span><span style="color: #000000">++</span><span style="color: #000000">;<br></span><span style="color: #008080">36</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; }<br></span><span style="color: #008080">37</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br></span><span style="color: #008080">38</span>&nbsp;<span style="color: #000000">}</span></div> <p><br>双核环境（Core2 E4500）修改之后的输出如下：</p> <p align="center"><a href="http://picasaweb.google.com/yulefox/Blog/photo#5189877484648302978"><img src="http://lh4.ggpht.com/yulefox/SAYmEzxCiYI/AAAAAAAAAJ4/822JVBb5o3s/s144/cpu_curve_sin_core2_cpu1.jpg">点击查看大图</a></p> <p>我理想中的表现是：</p> <p><font color="#800000">1) 曲线是平滑的，最好不因其他应用程序或操作的执行而改变；</font></p> <p><font color="#800000">2) 不管是单核还是双核，峰值皆为100%，谷值为0。</font></p> <p>对于第一点，其实就是保证任一刷新周期中的CPU占有率都可以被精确控制在0-100之间，如果你可以使CPU一直保持50%（而不是近似的上下波动），产生一条平滑的曲线就很easy了。</p> <p>问题的关键在于，除了当前你写的程序可以控制，其他程序或操作如何控制？或者说：<font color="#800000">如何控制CPU的运行情况才是关键之处</font>。</p> <p>PS: 一晚上老是断网，搞得思路频频被打断，兴致也损了大半。总之，《<a href="http://www.china-pub.com/38070" target="_blank">编程之美</a>》还是值得玩味一把吧:D。</p><img src ="http://www.cppblog.com/Fox/aggbug/47343.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-04-17 00:20 <a href="http://www.cppblog.com/Fox/archive/2008/04/17/control_cpu_using_curve.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何阅读、使用Blog?</title><link>http://www.cppblog.com/Fox/archive/2008/04/15/read_use_blog.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Tue, 15 Apr 2008 07:59:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/04/15/read_use_blog.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/47131.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/04/15/read_use_blog.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/47131.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/47131.html</trackback:ping><description><![CDATA[<p>Author: Fox</p> <p>本文写给满足以下条件的你（前面4点对应只读的你，后面4点对应只写的你)：</p> <p>1) 经常阅读别人的Blog，所谓经常，平均每天阅读量在100篇左右；</p> <p>2) 不希望花费大量时间在输入网址、鼠标点击和滚动上；</p> <p>3) 有固定的阅读习惯，指专注于某一领域、某些特定的Blog；</p> <p>4) 尚未使用或刚使用<a href="http://www.google.com/reader" target="_blank">Google Reader</a>并愿意使用<a href="http://www.google.com/reader" target="_blank">Google Reader</a>；</p> <p>5) 经常更新自己的Blog，所谓经常，平均每月更新1篇或以上；</p> <p>2) 不希望花费大量时间在复制、粘贴上；</p> <p>3) 希望多与其他人交流；</p> <p>4) 尚未使用或刚使用<a href="http://get.live.com/writer/overview" target="_blank">Windows Live Writer</a>并愿意使用<a href="http://get.live.com/writer/overview" target="_blank">Windows Live Writer</a>。</p> <p>1、For只读的你</p> <p>1) 启用<a href="http://www.google.com/reader" target="_blank">Google Reader</a></p> <p>做互联网的就是做互联网的，<a href="http://www.google.com/" target="_blank">Google</a>的<a href="http://www.google.com/reader" target="_blank">Google Reader</a>有个帐号就能开启。</p> <p>之前写过一个<a href="http://www.cppblog.com/Fox/articles/tutorial_for_gf.html" target="_blank">给我GF看的一点东西</a>，这儿对于启用<a href="http://www.google.com/reader" target="_blank">Google Reader</a>不再赘述了，有需要的TX可以看一下或者直接<a href="http://www.google.com/" target="_blank">Google</a>；</p> <p>2) 添加<a title="什么是RSS地址" href="http://baike.baidu.com/view/1644.htm" target="_blank">RSS地址</a></p> <p>首先要找到<a href="http://baike.baidu.com/view/1644.htm" target="_blank">RSS地址</a>，大多数网站提供的Blog，<a href="http://baike.baidu.com/view/1644.htm" target="_blank">RSS地址</a>都摆在显眼的地方，对于QQ空间这种算不上Blog的Blog来说，QQ空间的RSS也存在，比如，QQ号码为10000的用户，它的RSS就是：<a href="http://feeds.qzone.qq.com/cgi-bin/cgi_rss_out?uin=10000" target="_blank">http://feeds.qzone.qq.com/cgi-bin/cgi_rss_out?uin=10000</a>。</p> <p>找到<a href="http://baike.baidu.com/view/1644.htm" target="_blank">RSS地址</a>之后，就可以将其添加到订阅列表里面了。</p> <p>3) 关于<a title="什么是OPML" href="http://baike.baidu.com/view/127329.htm" target="_blank">OPML</a></p> <p>如果你想共享或备份你的订阅，<a href="http://www.google.com/reader" target="_blank">Google Reader</a>具有“导入/导出”功能，不提供具体的使用方式了，<a href="http://www.google.com/" target="_blank">Google</a>吧。</p> <p>4) 星标和标签</p> <p>看过的好文希望下次再读，就加个星标吧。</p> <p>RSS太多，就使用标签吧。</p> <p>觉得我这儿写的太简单，就<a href="http://www.google.com/" target="_blank">Google</a>吧，或者看看<a href="http://www.williamlong.info/archives/655.html" target="_blank">Google Reader的四个常用小技巧</a>。</p> <p>2、For只写的你</p> <p>1) 使用<a href="http://get.live.com/writer/overview" target="_blank">Windows Live Writer</a></p> <p>做软件的就是做软件的，Microsoft的这个<a href="http://get.live.com/writer/overview" target="_blank">Windows Live Writer</a>是要下载安装的。</p> <p>具体如何去用，下载下来自然就会用了。</p> <p>友情提示：<a href="http://get.live.com/writer/overview" target="_blank">Live Writer</a>的格式、超链接、查看、草稿、帐户、日志、分类列表，都很好用。</p> <p>2) 关于<a title="什么是CSS" href="http://baike.baidu.com/view/15916.htm" target="_blank">CSS</a></p> <p>我不太喜欢Blog的页面太乱，一会儿五号字，一会儿二号字，一会儿宋体，一会儿楷体。</p> <p>我喜欢把一些我认为<font color="#800000">重要的地方</font>和<a href="http://www.cppblog.com/fox/" target="_blank">链接的内容</a>突出显示，以前没添加<a title="什么是CSS" href="http://baike.baidu.com/view/15916.htm" target="_blank">CSS</a>的时候，每次都要自己去一个一个的修改链接的字体和颜色，浪费很多时间，如果你的Blog支持<a title="什么是CSS" href="http://baike.baidu.com/view/15916.htm" target="_blank">CSS</a>，就去看一下怎么使用吧，比如我的<a title="什么是CSS" href="http://baike.baidu.com/view/15916.htm" target="_blank">CSS</a>就很简单：</p> <p>&lt;style type=text/css&gt;<br>#top a{ border-bottom:1px dashed; color:white;&nbsp; }<br>#top a:link{ border-bottom:1px dashed; color:white; }<br>#top a:hover{ border-bottom:1px dashed; color:white; }<br>#top a:visited{ border-bottom:1px dashed; color:white; }<br>.post a:link{ border-bottom:1px dashed; color:maroon; }<br>.post a:hover{ border-bottom:1px dashed; color:maroon; }<br>.post a:visited{ border-bottom:1px dashed; color:maroon; }<br>.postbody a{ color:white; background:maroon;&nbsp; }<br>.postbody a:link{ color:white; background:maroon;&nbsp; }<br>.postbody a:hover{ color:white; background:maroon; }<br>.postbody a:visited{ color:white; background:maroon; }<br>&lt;/style&gt;  <p>我还使用了<a href="http://www.google.cn/search?complete=1&amp;hl=zh-CN&amp;newwindow=1&amp;q=devtoolbar&amp;meta=&amp;aq=0&amp;oq=devtoo" target="_blank">DevToolBar</a>帮助我确定了CSS。</p> <p>3) 添加Google专用的订阅</p> <p>我为此还专门PS了一张图片，你可以将下面的代码放到“<font color="#800000">公告</font>”里面，当然，你想放到哪儿就放到哪儿：</p> <p>&lt;br /&gt;订阅到：&lt;br /&gt;<br>&lt;a href="<a href="http://fusion.google.com/add?source=atgs&amp;feedurl=http%3A//www.cppblog.com/Fox/Rss.aspx&quot;">http://fusion.google.com/add?source=atgs&amp;feedurl=http%3A//www.cppblog.com/Fox/Rss.aspx"</a>&gt;&lt;img src="<a href="http://www.cppblog.com/images/cppblog_com/Fox/6064/o_GoogleRss.jpg&quot;">http://www.cppblog.com/images/cppblog_com/Fox/6064/o_GoogleRss.jpg"</a> border="0" alt="添加 游戏人生 到 Google 阅读器"&gt;&lt;/a&gt;&lt;br /&gt;  <p>我这儿是有图片的，只有文字的就是这样：</p> <p>&lt;br /&gt;订阅到：&lt;br /&gt;<br>&lt;a href="<a href="http://fusion.google.com/add?source=atgs&amp;feedurl=http%3A//www.cppblog.com/Fox/Rss.aspx">http://fusion.google.com/add?source=atgs&amp;feedurl=http%3A//www.cppblog.com/Fox/Rss.aspx"</a>&gt;添加 游戏人生 到 Google 阅读器&lt;/a&gt;&lt;br /&gt;  <p>上面的<a href="http://www.cppblog.com/Fox/Rss.aspx">www.cppblog.com/Fox/Rss.aspx</a>是我的<a title="什么是RSS地址" href="http://baike.baidu.com/view/1644.htm" target="_blank">RSS地址</a>，你要换成你的:-)。  <p>4) 关于邮箱地址  <p><font color="#800000">不要把邮箱地址直接放在页面上</font>，我之前曾经这样做，后面每天收到不少的垃圾邮件，就取消了，因为这年头，写个邮箱地址搜索器，然后发垃圾邮件太easy了。  <p>PS: 好用的东西还很多，因为我自己是GFans，所有在工作、学习和生活中使用了Analytics、Gmail、iGoogle、Picasa、Reader、Talk、笔记本、快讯、日历、网页历史记录、网站管理员工具、文件，反正都是免费的，而且用来比较方便，一个帐号可以搞定很多东西:D。</p><img src ="http://www.cppblog.com/Fox/aggbug/47131.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-04-15 15:59 <a href="http://www.cppblog.com/Fox/archive/2008/04/15/read_use_blog.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何产生随机数</title><link>http://www.cppblog.com/Fox/archive/2008/04/15/random_number_generator.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Tue, 15 Apr 2008 06:01:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/04/15/random_number_generator.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/47118.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/04/15/random_number_generator.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/47118.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/47118.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>
				<a href="http://en.wikipedia.org/wiki/John_von_Neumann" target="_blank">John von Neumann</a>说：<font color="#800000">Any one who considers arithmetical methods of producing random digits is , of course, in a state of sin.</font></p>
		<p>所以，在讨论算法实现随机数的时候，总是说“<font color="#800000">伪随机数</font>”。</p>
		<p>现在，应用最广的随机数生成算法是由<a href="http://en.wikipedia.org/wiki/Derrick_Henry_Lehmer" target="_blank">Derrick Henry Lehmer</a>1951年给出的<a href="http://en.wikipedia.org/wiki/Linear_congruential_generator" target="_blank">线性同余法</a>：</p>
		<p>              Xn+1 = ( aXn + c ) mod m,  n&gt;=0.</p>
		<p>在<a href="/Fox/archive/2008/04/03/mmorpg_security_prng.html" target="_blank">上一篇伪随机数的论述</a>中，并没有给出X0, a, c, m的取值规则，只是给出了<a href="http://en.wikipedia.org/wiki/ANSI_C" target="_blank">ANSI C</a>和<a href="http://en.wikipedia.org/wiki/Visual_C%2B%2B" target="_blank">Microsoft Visual C++</a>的实现。</p>
		<p>在这儿我们可以自己先思考一下，我们期望从上式中得到的随机数应该满足：</p>
		<p>
		</p>
		<p>1) 上式的输出足够随机，这是最基本的要求；</p>
		<p>2) 上式给出尽量多的输出，越接近m个越好（不可能超过m），即周期尽量长，最好为m，这样才能保证上式满足<font color="#800000">均匀分布</font>（<strike>m个数在周期m中各出现一次</strike>m个数出现的概率相等）；</p>
		<p>3) 上式的生成速度足够快。</p>
		<p>最容易想到的，<font color="#800000">m的取值为计算机字大小（如2^32或2^64）</font>。</p>
		<p>但是这儿有个很严重的问题：<font color="#800000">Xn低位的随机性很弱</font>。原因如下：</p>
		<p>令d|m, 且</p>
		<p>              Yn = Xn mod d</p>
		<p>则</p>
		<p>              Yn+1 = ( ( aXn + c ) mod m ) mod d</p>
		<p>                      = ( aYn + c ) mod d</p>
		<p>上述表达式的意义即：Yn为Xn低k位（d=2^k），这样的<font color="#800000">Yn序列形成周期为d甚至更短的同余序列</font>。举例说明：d为2^1时，Yn为Xn的最低位（可假定为1或0），若Yn+1 != Yn，则Yn+2 == Yn必定成立，仅当a、c皆为奇数时Yn、Yn+1将0、1交替，否则，为常数（0或1）。</p>
		<p>暂时抛开随机性不管，先找到周期为m的随机序列中的取值规则。</p>
		<p>
				<a href="http://en.wikipedia.org/wiki/Donald_Knuth">Donald Knuth</a>在<i>The Art of Computer Programming</i>, Volume 2: <em>Seminumerical Algorithms</em>中的<em>3.2.1.2</em>节对m, a, c和X0取值规则的表述：</p>
		<p>1) gcd(c, m) = 1. 即<font color="#800000">c, m互素</font>，再白一点，c, m除1之外没有其他公因子；</p>
		<p>2) 任给质数p, p|m ==&gt; p|(a-1). 即m%p==0，则(a-1)%p==0。</p>
		<p>3) 4|m ==&gt; 4|(a-1). 即m%4==0，则(a-1)%4==0。</p>
		<p>这个证明过程对于我这样的<font color="#800000"><a href="http://en.wikipedia.org/wiki/Number_theory" target="_blank">数论</a>基础</font>不是很扎实的搞应用技术的人来说有点难以理解了。有兴趣的话，还是去看<em>3.2.1.2</em>的证明吧:-)。</p>
		<p>上面的规则告诉我们，满足了上述规则后，可以保证序列周期为m。对于前面提到的关于随机性的问题，既然Xn低位的随机性比较弱，可以只取<font color="#800000">Xn的高位</font>作为输出。高位的<font color="#800000">随机性和统计意义</font>由a, c确定，其取值涉及<font color="#800000">统计检验</font>，具体的也还是看<em>3.3</em>吧。</p>
		<p>这篇文章解决了<font color="#800000">具有统计意义的随机数</font>的部分理论问题。</p>
		<p>PS: <a href="/Fox/archive/2008/03/06/mmorpg_net_iocp.html" target="_blank">之前曾经BS过Windows Live Writer</a>，当时觉得Writer编辑功能太少，<span style="COLOR: #800000">不能直接设定链接文字的字体颜色</span>，知道CSS可以设定之后，又觉得Word 2007编辑的Blog转成html之后太大，而且也知道Word 2007上面是可以设置链接的target为_blank的。现在发现Writer还是很不错的了，原来是<font color="#800000">可以设定格式</font>的，也可以直接编辑html，而且可以Web预览，链接还可以加入到<font color="#800000">链接词汇表</font>，挺方便的。</p>
		<p>越来越发现<a href="http://en.wikipedia.org/wiki/Main_Page" target="_blank">Wikipedia</a>是个和<a href="http://www.google.com/" target="_blank">Google</a>一样的好东西！</p><img src ="http://www.cppblog.com/Fox/aggbug/47118.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-04-15 14:01 <a href="http://www.cppblog.com/Fox/archive/2008/04/15/random_number_generator.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转贴：成都锦天科技（隶属上海盛大网络） 招聘信息！ </title><link>http://www.cppblog.com/Fox/archive/2008/04/11/invite_job.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Fri, 11 Apr 2008 04:41:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/04/11/invite_job.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/46825.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/04/11/invite_job.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/46825.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/46825.html</trackback:ping><description><![CDATA[<p>转自：<a href="/Bugs/archive/2008/04/01/45903.html">http://www.cppblog.com/Bugs/archive/2008/04/01/45903.html</a></p>
		<p>基本要求：<br />1、有软件工程思想,熟悉面向对象思想。<br />2、有良好的编码风格和文档编写习惯<br />3、熟悉C++语言,了解STL<br />4、了解多线程程序设计技术<br />5、热爱游戏、有游戏开发经验者优先<br />6、有团队开发精神优先<br /><br />客户端程序员：<br />1、了解DirectX编程技术，有良好的数学、各种算法基础优先<br />2、有图形开发经验者优先<br />3、熟悉UI编程技术优先<br />4、熟悉引擎开发者优先<br /><br />服务器端程序员：<br />1、熟悉通信以及网络安全技术. 熟悉TCP/IP协议及相关编程技术优先<br />2、有关系数据库编程及概念经验（MySql、PostgreSQL、MS Sql）<br />3、了解分布式服务器架构技术优先<br />4、了解Lua、Python有游戏脚本系统设计经验优先<br /><br />办公地点：成都<br />有意向的朋友跟贴或发简历到<a href="mailto:zhouhejian@snda.com">zhouhejian@snda.com</a></p><img src ="http://www.cppblog.com/Fox/aggbug/46825.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Fox/" target="_blank">Fox</a> 2008-04-11 12:41 <a href="http://www.cppblog.com/Fox/archive/2008/04/11/invite_job.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网络游戏安全思考——伪随机数篇</title><link>http://www.cppblog.com/Fox/archive/2008/04/03/mmorpg_security_prng.html</link><dc:creator>Fox</dc:creator><author>Fox</author><pubDate>Wed, 02 Apr 2008 18:35:00 GMT</pubDate><guid>http://www.cppblog.com/Fox/archive/2008/04/03/mmorpg_security_prng.html</guid><wfw:comment>http://www.cppblog.com/Fox/comments/46126.html</wfw:comment><comments>http://www.cppblog.com/Fox/archive/2008/04/03/mmorpg_security_prng.html#Feedback</comments><slash:comments>13</slash:comments><wfw:commentRss>http://www.cppblog.com/Fox/comments/commentRss/46126.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Fox/services/trackbacks/46126.html</trackback:ping><description><![CDATA[<p>Author: Fox</p>
		<p>一、随机数</p>
		<p>软件实现的<span style="COLOR: #800000">随机数生成器(random number generator, RNG)</span>生成的随机数列大多是<span style="COLOR: #800000">惟定数列</span>，因此一般被称作<span style="COLOR: #800000">伪随机数(pseudorandom number, PRN)</span>，而基于<span style="COLOR: #800000">热噪声(thermal noise)</span>、<span style="COLOR: #800000">光电效应(photoelectric effect)</span>、<span style="COLOR: #800000">放射性衰变(radioactive disintegration)</span>等不可预知的物理现象实现的<span style="COLOR: #800000">硬件随机数生成器(hardware random number generator)</span>生成的随机数才被认为是<span style="COLOR: #800000">真随机数(truly random number)</span>。PRN在计算机领域主要用于<span style="COLOR: #800000">仿真(simulation)和密码学(cryptography)。</span></p>
		<p>本文仅讨论伪随机数软件实现算法，并且仅讨论满足<span style="COLOR: #800000">均匀分布(uniform distribution, UD)</span>的伪随机数发生器(pseudorandom number generator, PRNG)。<span style="COLOR: #800000">非均匀分布(non-uniform distribution, NUD)</span>的PRNG可通过满足均匀分布的PRNG与非线性函数生成。</p>
		<p>本文讨论的PRNG应满足以下三点：</p>
		<p>a. 在取值空间内满足<span style="COLOR: #800000">UD</span>，即等概率取得取值空间内任意值。</p>
		<p>b. <span style="COLOR: #800000">充分随机</span>，即该随机数列周期(period)应尽量长。此点由所谓的<span style="COLOR: #800000">熵(entropy)</span>度量。</p>
		<p>c. <span styl