<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="http://unfoldingneurons.com/"
	>

<channel>
	<title>GoCalf Blog</title>
	<atom:link href="http://www.gocalf.com/blog/feed" rel="self" type="application/rss+xml" />
	<link>http://www.gocalf.com/blog</link>
	<description>1/100 Algo&#38;Math; 1/100 IT&#38;Game; 1/100 Info&#38;Sharing; 1/100 Personal&#38;Other.</description>
	<lastBuildDate>Tue, 15 May 2012 01:22:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2</generator>
		<item>
		<title>从大量整数中选取最小/大的若干个</title>
		<link>http://www.gocalf.com/blog/topn-of-massive-data.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=topn-of-massive-data</link>
		<comments>http://www.gocalf.com/blog/topn-of-massive-data.html#comments</comments>
		<pubDate>Tue, 17 Apr 2012 07:09:35 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[哈希排序]]></category>
		<category><![CDATA[堆排序]]></category>
		<category><![CDATA[快速选择]]></category>
		<category><![CDATA[海量数据]]></category>
		<category><![CDATA[选择算法]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1719</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/04/topn-selection.png" class="attachment-post-thumbnail wp-post-image" alt="topn-selection" title="topn-selection" /></div>问题描述：现在有非常大量的一堆对象，比如有几十亿甚至上百亿个。对象本身是什么可以忽略，每个对象都有唯一标识符和一个正整数属性值，属性值范围有限（不大于一亿）。在单核机器上，内存和磁盘空间充足，用什么方法可以最快地输出属性值最小的若干（如一万）个对象，要求输出结果按照属性值排序。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/04/topn-selection.png" class="attachment-post-thumbnail wp-post-image" alt="topn-selection" title="topn-selection" /></div><p>问题描述：现在有非常大量的一堆对象，比如有几十亿甚至上百亿个。对象本身是什么可以忽略，每个对象都有唯一标识符和一个正整数属性值，属性值范围有限（不大于一亿）。在单核机器上，内存和磁盘空间充足，用什么方法可以最快地输出属性值最小的若干（如一万）个对象，要求输出结果按照属性值排序。<span id="more-1719"></span></p>
<p>先说个题外话。前几天面试的时候，问了一个用栈模拟队列的题目，被candidate反问：这种问题在工作中会遇到么？有用么？</p>
<p>这个问题其实很好，值得我仔细思考。大体上来讲，我在面试的时候可能会这么几类问题（聊项目经验之类的除外）：</p>
<ol>
<li>某个编程语言的基础知识，如果candidate自称熟悉某语言；</li>
<li>常见的数据结构，用来大概了解candidate的基本功；</li>
<li>基本的编程题目，考察他的写代码能力；</li>
<li>数学或算法问题，一方面了解candidate的基本功，另一方面看看他的思维能力和解决问题的能力；</li>
<li>一些从实际工作中抽象出来的，相对而言比较开放的题目，主要是看他分析问题和解决问题的能力。</li>
</ol>
<p>今天这个题目是我最近比较喜欢的一个问题，是曾经在工作中遇到过的。</p>
<p>先来看看题目中出现的数字带来什么信息。</p>
<ul>
<li>对象的个数（设为n），十亿甚至百亿：也就是10^9到10^10这样的量级，已经接近甚至超过32位整数的范围。即使每个对象只占用1字节，总共也需要1G到10G的空间。</li>
<li>对象属性值的范围，正整数，一亿：相对于个数，属性值的范围还是相当有限的，最多有100M个各不相同的值，可以用32位整数表示。</li>
<li>要求选取的对象个数（设为m），一万左右：相对于个数来说是非常非常小的。</li>
</ul>
<p>可见，单单保存所有的属性值也需要4G到40G的空间。标识符最少也得用64位整数表示，又需要8G到80G的空间。</p>
<p>在这种特殊的要求下，怎么处理是最高效的呢？来看看以下的几种方法。</p>
<h3>方法一：快速选择/线性选择算法</h3>
<p>快速选择和线性选择算法都是平均时间复杂度O(n)的选择算法，当然线性选择算法在最坏情况下也能保证O(n)时间，缺点是实现起来比较复杂。简单起见，我就用快速选择算法。</p>
<p>快速选择算法类似于快速排序，用一个轴值将数组分成两部分，一部分全都比轴值小，而另一部分全都比轴值大。然后看看两部分分别包含多少个元素，从而确定第m大的元素应该再哪一半，然后对那一半递归处理，直到找到第m大的元素。</p>
<p>但是将快速选择算法应用到本题时，遇到主要问题是内存恐怕不够。</p>
<p>如果在内存中放入所有的对象，我们需要12G到120G内存，取决于对象的个数是十亿还是一百亿。进入内存后，还需要至少两次遍历才可以找到第m大的元素。另外加载数据时需要有一次完整的文件遍历。</p>
<p>如果内存中无法放入所有的对象，那就比较麻烦了，在头几次二分递归的时候可能需要动用硬盘来缓存数据，磁盘IO将成为可怕的瓶颈。累加起来相当于至少两次全文件的读遍历和写遍历。实际上，在确定了第m大的对象后，可能还需要遍历一次整个文件，找出比它小的对象。</p>
<h3>方法二：堆排序算法</h3>
<p>堆排序也是一个很好的可以用于部分排序的算法，C++ STL就用堆排序来实现partial_sort。</p>
<p>在内存中维护一个大小为m的最大值堆（没错，是最大值堆），遍历整个文件，每拿到一个对象，拿它与堆顶的属性值比较一下，如果新对象的属性值大就直接丢弃，否则用它取代堆顶元素。平均来讲，这样处理的时间复杂度是n * log m。</p>
<h3>方法三：哈希算法</h3>
<p>我们注意到，虽然对象的个数非常大，但属性值的范围非常小（相对来讲）。如果在值域范围上建立一个哈希表，只需要100M个格子，如果一个格子存储一个32位整数，只需要400M内存。</p>
<p>哈希表总是会有冲突的，在这个问题中，冲突是必然的，平均每个属性值上会有10到100个不同的对象。但处理冲突的办法非常简单，因为我们不需要在哈希表中记录每个对象，只需要记录这个属性值对应的对象的个数。</p>
<p>开辟一个能存放100M个32位整数的数组（为保险起见，可以用64位整数，但总共也只需要800M内存），数组的下标对应于属性值（实际操作中可能要减一）。然后遍历整个文件，每拿到一个对象，将对应的数组元素值加一。</p>
<p>文件遍历完后，过一下这个数组，可以找出第m大的对象的属性值，这个值就是一个边界。然后再遍历一次原始文件，把属性值小于等于边界的对象都放到内存中（注意在相等时，会有个数的限制）。最后把内存中的m个对象按照属性值排一下序再输出即可。</p>
<p>这样最多只需要遍历两次文件，使用O(n)时间就可以完成题目的要求。</p>
<h3>到底哪个方法快？</h3>
<p>上面提到了三种算法，到底哪一个最快呢？说说你的看法吧？</p>
<p>我以前一直觉得哈希法是最快的，它对内存的需求量适中，算法是线性时间。但后来又仔细想了想，觉得不太对。这里实际上不完全是内存中的运算了，瓶颈主要是在磁盘IO上。</p>
<p>让我们来比较一下三种算法：</p>
<ol>
<li>快速选择算法（所有对象可以全进内存）：只需要一次文件读遍历，内存操作是O(n)时间（系数至少为2，可能会很大）。</li>
<li>快速选择算法（只有部分对象可进内存）：平均需要三次文件读遍历，两次写遍历，内存操作是O(n)时间（系数至少为2，可能会很大）。</li>
<li>堆排序算法：需要一次文件读遍历，内存操作是O(n * log m)时间，这里m取10000的话，大概是13。当然实际数值会少于13，因为并不是每个对象都需要进入堆中。</li>
<li>哈希算法（所有对象可以全进内存）：需要一次文件读遍历，在内存中要开辟大小为O(n)和O(m)的两块缓冲区，内存操作时间为O(n)（系数大约为2）。</li>
<li>哈希算法（只有部分对象可进内存）：需要两次文件读遍历，内存操作是O(n)时间（系数小于2）。</li>
</ol>
<p>题目的本意就是几乎不可能让所有对象都进入内存。虽然堆排序的内存操作时间复杂度偏高，却只需要一次磁盘遍历操作，其消耗的时间应该要小于哈希算法的。你是否同意呢？</p>
<p>最近做了个实验，生成了十亿个对象，每个对象有一个64位整数作为标识符，还有一个不超过一亿的随机整数作为属性值。生成的文件用文本格式存储，占用18G磁盘空间。我没有实验快速选择算法，只是比较了堆排序和哈希。实验结果是：</p>
<ul>
<li>单纯遍历一次文件，包括逐行读取，把属性值解析成整数：耗时34分钟；</li>
<li>堆排序算法：耗时40分钟；</li>
<li>哈希算法：耗时73分钟。</li>
</ul>
<p>这三个时间的相对值是否在你的预料之中呢？</p>
<p>当然，如果把硬盘换成SSD恐怕结果又完全不同了，有兴趣的童鞋可以试一试。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/topn-of-massive-data.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>程序基本功之遍历二叉树</title>
		<link>http://www.gocalf.com/blog/traversing-binary-tree.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=traversing-binary-tree</link>
		<comments>http://www.gocalf.com/blog/traversing-binary-tree.html#comments</comments>
		<pubDate>Wed, 04 Apr 2012 08:51:20 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[二叉树]]></category>
		<category><![CDATA[栈]]></category>
		<category><![CDATA[递归]]></category>
		<category><![CDATA[遍历二叉树]]></category>
		<category><![CDATA[队列]]></category>
		<category><![CDATA[非递归遍历]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1701</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/04/traverse-bin-tree.png" class="attachment-post-thumbnail wp-post-image" alt="traverse-bin-tree" title="traverse-bin-tree" /></div>最近工作忙，没时间思考复杂的问题了。正好要招人就得有面试的嘛，自己也温习一下，要不然怎么去问别人。

今天复习一下二叉树的遍历，前序（pre-order，NLR）、中序（in-order，LNR）、后序（post-order，LRN）、层序（level-order），用和不用递归。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/04/traverse-bin-tree.png" class="attachment-post-thumbnail wp-post-image" alt="traverse-bin-tree" title="traverse-bin-tree" /></div><p>最近工作忙，没时间思考复杂的问题了。正好要招人就得有面试的嘛，自己也温习一下，要不然怎么去问别人。</p>
<p>今天复习一下二叉树的遍历，前序（pre-order，NLR）、中序（in-order，LNR）、后序（post-order，LRN）、层序（level-order），用和不用递归。<span id="more-1701"></span></p>
<p>概念就不用多解释了，前、中、后是指根结点的访问时机，在左、右子树之前、中间、或之后。层序就是从根结点开始从上至下、从左到右地依次访问。</p>
<div id="attachment_1707" class="wp-caption alignnone" style="width: 575px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2012/04/bin-tree.png" alt="bin-tree" title="bin-tree" width="565" height="347" class="size-full wp-image-1707 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">一棵二叉树</p></div>
<p>如上图所示的一棵二叉树，对应的遍历结果分别是：</p>
<ul>
<li>前序（NLR）：<code class="codecolorer text geshi"><span class="text">A B D C E G H F I</span></code></li>
<li>中序（LNR）：<code class="codecolorer text geshi"><span class="text">D B A G E H C F I</span></code></li>
<li>后序（LRN）：<code class="codecolorer text geshi"><span class="text">D B G H E I F C A</span></code></li>
<li>层序：<code class="codecolorer text geshi"><span class="text">A B C D E F G H I</span></code></li>
</ul>
<h3>一、用递归处理二叉树的前序、中序和后序遍历</h3>
<p>递归真是一个迷人东西，它可以把复杂的逻辑变得异常简洁，这也是自然界的表现形式之一。基于递归的前、中、后序遍历二叉树的程序几乎完全相同，用两个递归调用分别处理左、右子树，剩下的事情就是打印根结点。为节省篇幅，直接把三个程序写在一起，用一个参数来控制是哪种遍历方式，也可以更方便地看出三者之间的区别。</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> VisitTree_Recursive<span style="color: black;">&#40;</span>root<span style="color: #66cc66;">,</span> order<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> root:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> order <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'NLR'</span>: <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>root.<span style="color: black;">data</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; VisitTree_Recursive<span style="color: black;">&#40;</span>root.<span style="color: black;">left</span><span style="color: #66cc66;">,</span> order<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> order <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'LNR'</span>: <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>root.<span style="color: black;">data</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; VisitTree_Recursive<span style="color: black;">&#40;</span>root.<span style="color: black;">right</span><span style="color: #66cc66;">,</span> order<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> order <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'LRN'</span>: <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>root.<span style="color: black;">data</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div></pre>
<h3>二、非递归的前序、中序遍历</h3>
<p>如果不用递归呢？实际上我们要做的就是自己维护一个栈（数据结构）来保存需要但尚未来得及处理的数据。</p>
<p>前序和中序都是非常简单的，当遇到一个非空的根结点时，打印其数据（如果是前序遍历），并将其压栈，然后递归地（这里用循环来模拟递归）处理其左子结点；当没有左子结点时，从栈中弹出之前遇到的某个根结点（它没有做子结点，或者左子结点已经处理完毕，需要再处理右子结点），打印数据（如果是中序遍历），然后继续处理右子结点。同样地，把两种遍历方式写在一起以便比较。</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> VisitTree<span style="color: black;">&#40;</span>root<span style="color: #66cc66;">,</span> order<span style="color: black;">&#41;</span>:<br />
&nbsp; s <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> root <span style="color: #ff7700;font-weight:bold;">or</span> s:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> root:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> order <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'NLR'</span>: <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>root.<span style="color: black;">data</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; s.<span style="color: black;">append</span><span style="color: black;">&#40;</span>root<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; root <span style="color: #66cc66;">=</span> root.<span style="color: black;">left</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; root <span style="color: #66cc66;">=</span> s.<span style="color: black;">pop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> order <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'LNR'</span>: <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>root.<span style="color: black;">data</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; root <span style="color: #66cc66;">=</span> root.<span style="color: black;">right</span></div></td></tr></tbody></table></div></pre>
<h3>三、非递归的后序遍历</h3>
<p>后序遍历要稍微复杂一点点，在前序和中序遍历的程序中，当我们准备进入根结点的右子树时，根结点就被扔出栈外了。但在后序遍历时，我们仍需保留它，直到右子树处理完毕。</p>
<p>首先想到的改动就是在上面的程序的第9行到11行，不要从栈s中将根结点弹出，而是直接开始处理右子结点。但这就会带来一个问题：什么时候弹出根结点？实际上当左子树遍历完成、或者右子树遍历完成时，我们都会在栈里看到根结点，为了区分这两种状态，添加一个临时变量记录前一次访问的结点，如果前一个结点是根结点的右子树，就说明左右子树全都遍历完成了。非常简单。</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> VisitTreeLRN<span style="color: black;">&#40;</span>root<span style="color: black;">&#41;</span>:<br />
&nbsp; s <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; pre <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> root <span style="color: #ff7700;font-weight:bold;">or</span> s:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> root:<br />
&nbsp; &nbsp; &nbsp; s.<span style="color: black;">append</span><span style="color: black;">&#40;</span>root<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; root <span style="color: #66cc66;">=</span> root.<span style="color: black;">left</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">elif</span> s<span style="color: black;">&#91;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>.<span style="color: black;">right</span> <span style="color: #66cc66;">!=</span> pre:<br />
&nbsp; &nbsp; &nbsp; root <span style="color: #66cc66;">=</span> s<span style="color: black;">&#91;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>.<span style="color: black;">right</span><br />
&nbsp; &nbsp; &nbsp; pre <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; pre <span style="color: #66cc66;">=</span> s.<span style="color: black;">pop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>pre.<span style="color: black;">data</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div></pre>
<h3>四、非递归的层序遍历</h3>
<p>层序遍历可以写成递归吗？还真没研究过。非递归的时候，层序遍历使用的是队列，而非栈。</p>
<p>处理过程非常简明，遇到一个结点，打印信息，然后依次将左、右子结点加入队列等待后续处理。</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">collections</span> <span style="color: #ff7700;font-weight:bold;">import</span> deque<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> VisitTree_LevelOrder<span style="color: black;">&#40;</span>root<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> root: <span style="color: #ff7700;font-weight:bold;">return</span><br />
&nbsp; q <span style="color: #66cc66;">=</span> deque<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>root<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> q:<br />
&nbsp; &nbsp; root <span style="color: #66cc66;">=</span> q.<span style="color: black;">popleft</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>root.<span style="color: black;">data</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> root.<span style="color: black;">left</span>: q.<span style="color: black;">append</span><span style="color: black;">&#40;</span>root.<span style="color: black;">left</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> root.<span style="color: black;">right</span>: q.<span style="color: black;">append</span><span style="color: black;">&#40;</span>root.<span style="color: black;">right</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div></pre>
<h3>附录</h3>
<p>上面的python代码基于v2.7。另外可以用下面这段代码来定义最简单的二叉树结点类，生成最上面图示的二叉树：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> Node:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> data<span style="color: #66cc66;">,</span> left <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> right <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">data</span> <span style="color: #66cc66;">=</span> data<br />
&nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">left</span> <span style="color: #66cc66;">=</span> left<br />
&nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">right</span> <span style="color: #66cc66;">=</span> right<br />
<br />
g <span style="color: #66cc66;">=</span> Node<span style="color: black;">&#40;</span><span style="color: #483d8b;">'G'</span><span style="color: black;">&#41;</span><br />
h <span style="color: #66cc66;">=</span> Node<span style="color: black;">&#40;</span><span style="color: #483d8b;">'H'</span><span style="color: black;">&#41;</span><br />
e <span style="color: #66cc66;">=</span> Node<span style="color: black;">&#40;</span><span style="color: #483d8b;">'E'</span><span style="color: #66cc66;">,</span> g<span style="color: #66cc66;">,</span> h<span style="color: black;">&#41;</span><br />
i <span style="color: #66cc66;">=</span> Node<span style="color: black;">&#40;</span><span style="color: #483d8b;">'I'</span><span style="color: black;">&#41;</span><br />
f <span style="color: #66cc66;">=</span> Node<span style="color: black;">&#40;</span><span style="color: #483d8b;">'F'</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> i<span style="color: black;">&#41;</span><br />
c <span style="color: #66cc66;">=</span> Node<span style="color: black;">&#40;</span><span style="color: #483d8b;">'C'</span><span style="color: #66cc66;">,</span> e<span style="color: #66cc66;">,</span> f<span style="color: black;">&#41;</span><br />
d <span style="color: #66cc66;">=</span> Node<span style="color: black;">&#40;</span><span style="color: #483d8b;">'D'</span><span style="color: black;">&#41;</span><br />
b <span style="color: #66cc66;">=</span> Node<span style="color: black;">&#40;</span><span style="color: #483d8b;">'B'</span><span style="color: #66cc66;">,</span> d<span style="color: black;">&#41;</span><br />
a <span style="color: #66cc66;">=</span> Node<span style="color: black;">&#40;</span><span style="color: #483d8b;">'A'</span><span style="color: #66cc66;">,</span> b<span style="color: #66cc66;">,</span> c<span style="color: black;">&#41;</span><br />
root <span style="color: #66cc66;">=</span> a</div></td></tr></tbody></table></div></pre>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/least-common-ancestor.html' rel='bookmark' title='求二叉树中两结点的最小公共祖先'>求二叉树中两结点的最小公共祖先</a></li>
<li><a href='http://www.gocalf.com/blog/circularly-ordinal-array.html' rel='bookmark' title='在循环有序数组中查找指定元素'>在循环有序数组中查找指定元素</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/traversing-binary-tree.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>iPhone开发：可拉伸的图片</title>
		<link>http://www.gocalf.com/blog/iphone-dev-resizable-image.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=iphone-dev-resizable-image</link>
		<comments>http://www.gocalf.com/blog/iphone-dev-resizable-image.html#comments</comments>
		<pubDate>Sat, 10 Mar 2012 14:57:09 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[程序开发]]></category>
		<category><![CDATA[End Cap]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPhone 开发]]></category>
		<category><![CDATA[ObjC]]></category>
		<category><![CDATA[Resizable Image]]></category>
		<category><![CDATA[Stretchable Image]]></category>
		<category><![CDATA[UIImage]]></category>
		<category><![CDATA[图片拉伸]]></category>
		<category><![CDATA[端帽]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1680</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/03/resizable_image_icon.png" class="attachment-post-thumbnail wp-post-image" alt="resizable_image_icon" title="resizable_image_icon" /></div>还记得在Windows下用MFC或WTL写用户界面程序的时候，为了给可改变大小的对话框加上背景图案，需要对设计师提供的图片进行裁剪。把图片切成九块，其中四个角是不拉伸的，四条棱边可以在一个方向上拉伸，中间区域则可任意拉伸。其过程是相当烦琐的。在Mac下，一切都变的及其简单，UIImage类已经为我们提供了处理拉伸的方法。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/03/resizable_image_icon.png" class="attachment-post-thumbnail wp-post-image" alt="resizable_image_icon" title="resizable_image_icon" /></div><p>还记得在Windows下用MFC或WTL写用户界面程序的时候，为了给可改变大小的对话框加上背景图案，需要对设计师提供的图片进行裁剪。把图片切成九块，其中四个角是不拉伸的，四条棱边可以在一个方向上拉伸，中间区域则可任意拉伸。其过程是相当烦琐的。在Mac下，一切都变的及其简单，<a href="https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/" target="_blank">UIImage</a>类已经为我们提供了处理拉伸的方法。<span id="more-1680"></span></p>
<p>以下内容适用于iOS 2.0+，或在iOS 5.0+中使用替换的方法。</p>
<p>UIImage有一个叫做端帽（end cap）的概念，利用它来指定图片中哪一部分（通常在图片的中央）是可以拉伸的，哪些部分（四周一圈）不可拉伸。在iOS 5.0以前，通过<a href="https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIImage_Class/DeprecationAppendix/AppendixADeprecatedAPI.html#//apple_ref/occ/instm/UIImage/stretchableImageWithLeftCapWidth:topCapHeight:" target="_blank">stretchableImageWithLeftCapWidth:topCapHeight:</a>来得到可以按照指定方式拉伸的图片。特别要注意的一点，我在第一次用它的时候没有注意到，就是这个方法并不会改变当前的UIImage实例，而是会返回一个新的实例。这样的设计可能是为了让通过imageNamed方法得到的UIImage实例能够最大限度地复用吧。</p>
<p>stretchableImage方法有两个整数参数，分别用来指定图片的左边和上边分别有多少点（points）是不能被拉伸的（端帽宽度）。并没有参数用来指定右边和下边的端帽宽度，开始我<strong>误以为</strong>右边和下边的端帽宽度就分别等于左边和上边的端帽宽度，然而仔细阅读官方文档之后发现并非如此：</p>
<blockquote>
<p>The middle (stretchable) portion is assumed to be 1 pixel wide. The right end cap is therefore computed by adding the size of the left end cap and the middle portion together and then subtracting that value from the width of the image:</p>
<pre><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rightCapWidth <span style="color: #002200;">=</span> image.size.width <span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>image.leftCapWidth <span style="color: #002200;">+</span> <span style="color: #2400d9;">1</span><span style="color: #002200;">&#41;</span>;</div></div></pre>
<p>The middle (stretchable) portion is assumed to be 1 pixel wide. The bottom end cap is therefore computed by adding the size of the top end cap and the middle portion together and then subtracting that value from the height of the image:</p>
<pre><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">bottomCapHeight <span style="color: #002200;">=</span> image.size.height <span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>image.topCapHeight <span style="color: #002200;">+</span> <span style="color: #2400d9;">1</span><span style="color: #002200;">&#41;</span>;</div></div></pre>
</blockquote>
<p>原来已经规定了中间可拉伸区域必须是1x1的，因此右边和下边的端帽宽度就由图片的宽度和高度、左边和上边的端帽宽度决定。在设计非对称图案时需要注意一下。</p>
<p>从iOS 5.0开始，stretchableImage方法被弃用，取而代之的是<a href="https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIImage_Class/Reference/Reference.html#//apple_ref/occ/instm/UIImage/resizableImageWithCapInsets:" target="_blank">resizableImageWithCapInsets:</a>。后者只需要一个UIEdgeInsets类型的参数，通过此参数，可以设置四个端帽的宽度。而中心剩余的部分都是可以拉伸的（不再局限于1x1大小）。</p>
<p>下面这个程序片段给试图添加了三个UIImageView，分别显示原始大小的图片、无端帽拉伸之后的图片、和指定了正确的端帽宽度（用stretchableImage）后拉伸的图片。</p>
<pre><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>viewDidLoad<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; <span style="color: #002200;">&#91;</span>super viewDidLoad<span style="color: #002200;">&#93;</span>;<br />
&nbsp; <span style="color: #11740a; font-style: italic;">// Do any additional setup after loading the view, typically from a nib.</span><br />
&nbsp; <br />
&nbsp; UIImage<span style="color: #002200;">*</span> image <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>UIImage imageNamed<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;circle.png&quot;</span><span style="color: #002200;">&#93;</span>;<br />
<span style="display:block;background-color:#ffff66">&nbsp; UIImage<span style="color: #002200;">*</span> stretchableImage <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>image stretchableImageWithLeftCapWidth<span style="color: #002200;">:</span><span style="color: #2400d9;">10</span><br /></span><span style="display:block;background-color:#ffff66">&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;topCapHeight<span style="color: #002200;">:</span><span style="color: #2400d9;">10</span><span style="color: #002200;">&#93;</span>;<br /></span>&nbsp; <br />
&nbsp; UIImageView<span style="color: #002200;">*</span> imageView1 <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIImageView alloc<span style="color: #002200;">&#93;</span> initWithImage<span style="color: #002200;">:</span>image<span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;autorelease<span style="color: #002200;">&#93;</span>;<br />
&nbsp; imageView1.center <span style="color: #002200;">=</span> CGPointMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">20</span>, <span style="color: #2400d9;">20</span><span style="color: #002200;">&#41;</span>;<br />
&nbsp; <span style="color: #002200;">&#91;</span>self.view addSubview<span style="color: #002200;">:</span>imageView1<span style="color: #002200;">&#93;</span>;<br />
&nbsp; <br />
&nbsp; UIImageView<span style="color: #002200;">*</span> imageView2 <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIImageView alloc<span style="color: #002200;">&#93;</span> initWithImage<span style="color: #002200;">:</span>image<span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;autorelease<span style="color: #002200;">&#93;</span>;<br />
&nbsp; imageView2.frame <span style="color: #002200;">=</span> CGRectMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">0</span>, <span style="color: #2400d9;">0</span>, <span style="color: #2400d9;">260</span>, <span style="color: #2400d9;">200</span><span style="color: #002200;">&#41;</span>;<br />
&nbsp; imageView2.center <span style="color: #002200;">=</span> CGPointMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">160</span>, <span style="color: #2400d9;">120</span><span style="color: #002200;">&#41;</span>;<br />
&nbsp; <span style="color: #002200;">&#91;</span>self.view addSubview<span style="color: #002200;">:</span>imageView2<span style="color: #002200;">&#93;</span>;<br />
&nbsp; <br />
&nbsp; UIImageView<span style="color: #002200;">*</span> imageView3 <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIImageView alloc<span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; initWithImage<span style="color: #002200;">:</span>stretchableImage<span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;autorelease<span style="color: #002200;">&#93;</span>;<br />
&nbsp; imageView3.frame <span style="color: #002200;">=</span> CGRectMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">0</span>, <span style="color: #2400d9;">0</span>, <span style="color: #2400d9;">260</span>, <span style="color: #2400d9;">200</span><span style="color: #002200;">&#41;</span>;<br />
&nbsp; imageView3.center <span style="color: #002200;">=</span> CGPointMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">160</span>, <span style="color: #2400d9;">340</span><span style="color: #002200;">&#41;</span>;<br />
&nbsp; <span style="color: #002200;">&#91;</span>self.view addSubview<span style="color: #002200;">:</span>imageView3<span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></pre>
<p>运行后效果如下图示：</p>
<div id="attachment_1693" class="wp-caption alignnone" style="width: 330px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2012/03/resizable_image.png" alt="resizable_image" title="resizable_image" width="320" height="480" class="size-full wp-image-1693 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">UIImage拉伸示意（左上角：原始图片；上：直接拉伸；下：按照端帽拉伸）</p></div>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/iphone-dev-range-slider.html' rel='bookmark' title='iPhone开发：自定义控件RangeSlider（范围滑动条）'>iPhone开发：自定义控件RangeSlider（范围滑动条）</a></li>
<li><a href='http://www.gocalf.com/blog/iphone-dev-hide-status-bar.html' rel='bookmark' title='iPhone开发：隐藏系统状态栏'>iPhone开发：隐藏系统状态栏</a></li>
<li><a href='http://www.gocalf.com/blog/iphone-dev-progressview-in-alertview.html' rel='bookmark' title='iPhone开发：在UIAlertView中显示进度条'>iPhone开发：在UIAlertView中显示进度条</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/iphone-dev-resizable-image.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[iOS开发笔记]]></series:name>
	</item>
		<item>
		<title>解决黑苹果Unable to Determine UUID错误</title>
		<link>http://www.gocalf.com/blog/hackintosh-fix-uuid.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=hackintosh-fix-uuid</link>
		<comments>http://www.gocalf.com/blog/hackintosh-fix-uuid.html#comments</comments>
		<pubDate>Fri, 02 Mar 2012 15:09:34 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[操作系统]]></category>
		<category><![CDATA[genstrings]]></category>
		<category><![CDATA[Hackintosh]]></category>
		<category><![CDATA[Localizable.strings]]></category>
		<category><![CDATA[Unable to Determine UUID]]></category>
		<category><![CDATA[UUID]]></category>
		<category><![CDATA[黑苹果]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1662</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/03/uuid-icon.png" class="attachment-post-thumbnail wp-post-image" alt="uuid-icon" title="uuid-icon" /></div>前几天在写app的最后阶段要进行本地化（localization），其中要做的一件事就是创建语言文件（Localizable.strings）。要在控制台运行genstrings命令来扫描源代码中NSLocalizedString宏所使用到的文字。由于使用的是黑苹果，在运行genstrings时遇到了“Unable to Determine UUID”的错误，解决方法倒也容易。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/03/uuid-icon.png" class="attachment-post-thumbnail wp-post-image" alt="uuid-icon" title="uuid-icon" /></div><p>前几天在写app的最后阶段要进行本地化（localization），其中要做的一件事就是创建语言文件（Localizable.strings）。要在控制台运行genstrings命令来扫描源代码中NSLocalizedString宏所使用到的文字。由于使用的是黑苹果（安装过程参见<a href="http://www.gocalf.com/blog/dell-e6400-install-mac.html">这里</a>和<a href="http://www.gocalf.com/blog/dell-e6400-mac-10-6-8.html">这里</a>），在运行genstrings时遇到了“Unable to Determine UUID”的错误，解决方法倒也容易。</p>
<p><span id="more-1662"></span></p>
<p>运行genstrings的语句是：</p>
<pre><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">genstrings ./Classes/*.m</div></div></pre>
<p>得到了这样的错误信息：</p>
<pre><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">genstrings[3851:10b] _CFGetHostUUIDString: unable to determine UUID for host. Error: 35</div></div></pre>
<p>虽然想不通这么个小程序为什么需要UUID，但解决方法是：进入目录<code class="codecolorer text geshi"><span class="text">/Library/Preferences/SystemConfiguration</span></code>，用root权限修改其中的<code class="codecolorer text geshi"><span class="text">NetworkInterfaces.plist</span></code>文件，在控制台的操作命令为：</p>
<pre><div class="codecolorer-container bash geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #000000; font-weight: bold;">/</span>Library<span style="color: #000000; font-weight: bold;">/</span>Preferences<span style="color: #000000; font-weight: bold;">/</span>SystemConfiguration<br />
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">vi</span> NetworkInterfaces.plist</div></div></pre>
<p>给这个文件中添加一个IEEE80211相关的dict（原本会有其他一些dict，不用管它们），内容如下：</p>
<pre><div class="codecolorer-container xml geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dict<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>BSD Name<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>en3<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>IOBuiltin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;false</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>IOInterfaceType<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;integer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>6<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/integer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>IOInterfaceUnit<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;integer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>3<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/integer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>IOLocation<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>IOMACAddress<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;data<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>ABbPoF5V<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/data<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>IOPathMatch<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/P0P3@1C,2/IOPCI2PCIBridge/pci14e4,4311@0/AirPort_Brcm43xx/IO80211Interface<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>SCNetworkInterfaceType<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>IEEE80211<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dict<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div></pre>
<p>添加好后保存此文件，然后重启系统。问题就解决了。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/dell-e6400-install-mac.html' rel='bookmark' title='Dell E6400安装MacOS雪豹10.6'>Dell E6400安装MacOS雪豹10.6</a></li>
<li><a href='http://www.gocalf.com/blog/cpp-const-and-pointer.html' rel='bookmark' title='C++中的常量指针和指针常量'>C++中的常量指针和指针常量</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/hackintosh-fix-uuid.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>最经典的光线反射游戏Chromatron</title>
		<link>http://www.gocalf.com/blog/chromatron.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=chromatron</link>
		<comments>http://www.gocalf.com/blog/chromatron.html#comments</comments>
		<pubDate>Fri, 10 Feb 2012 16:14:56 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[游戏]]></category>
		<category><![CDATA[Chromatron]]></category>
		<category><![CDATA[光线反射]]></category>
		<category><![CDATA[反光镜]]></category>
		<category><![CDATA[显像管]]></category>
		<category><![CDATA[游戏攻略]]></category>
		<category><![CDATA[益智游戏]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1641</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/02/chromatron_icon.png" class="attachment-post-thumbnail wp-post-image" alt="chromatron_icon" title="chromatron_icon" /></div>Chromatron，翻译过来是彩色显像管。顾名思义，这个游戏是关于光线反射的。在网络中还流传着很多这个游戏的Flash版，都是山寨的，抄袭了这个游戏的关卡和操作方式。

这是个相当古老的游戏了，好多年前就玩了它的第一代和第二代，后来又陆续玩了第三代和第四代。第三代有几关是前些日子才玩出来的，整理一下留作纪念。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/02/chromatron_icon.png" class="attachment-post-thumbnail wp-post-image" alt="chromatron_icon" title="chromatron_icon" /></div><p>Chromatron，翻译过来是彩色显像管。顾名思义，这个游戏是关于光线反射的。在网络中还流传着很多这个游戏的Flash版，都是山寨的，抄袭了这个游戏的关卡和操作方式。</p>
<p>这是个相当古老的游戏了，好多年前就玩了它的第一代和第二代，后来又陆续玩了第三代和第四代。第三代有几关是前些日子才玩出来的，整理一下留作纪念。<span id="more-1641"></span></p>
<p>游戏的官方网站是：<a href="http://silverspaceship.com/chromatron/" target="_blank">http://silverspaceship.com/chromatron/</a>，可以下载到Chromatron第一代到第四代的最新版本，Windows系统和Mac OS都支持哦。</p>
<p>我这里也提供Windows版的下载：</p>
<ol>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2012/02/chromatron1_v1.14.zip">Chromatron 1代 v1.14</a></li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2012/02/chromatron2_v1.5.zip">Chromatron 2代 v1.5</a></li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2012/02/chromatron3_v1.1.zip">Chromatron 3代 v1.1</a></li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2012/02/chromatron4_v1.0.zip">Chromatron 4代 v1.0</a></li>
</ol>
<p>这个游戏中除了反射镜、三棱镜等传统光学元件外，还有一些现实中不一定存在的非常神奇的元件，比如多普勒仪（Doppler），如果红色光线从一端射入，另一端就会射出绿色光线，类似地，绿色光线会变成蓝色，而蓝色会变成红色。如果反过来使用，颜色的变化也反之。再比如量子纠缠分光器（Quantum Tangler），它将输入的光线变成两条向相反方向射出的光线，并且这两条光线是量子纠缠的，其中一条光线被多普勒仪改变颜色时，另外那条光线就会变为相反的颜色。又如可移动的光线传送器（Mobile Teleporter），成对使用时，可以将其中一个接收到的光线传送到另一个。还有逻辑门（Logic Gate）、互补器（Complementor）等等。所有的元件如下图示。</p>
<div id="attachment_1650" class="wp-caption alignnone" style="width: 142px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2012/02/chromatron_elems.png" alt="chromatron_elems" title="chromatron_elems" width="132" height="80" class="size-full wp-image-1650 wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">Chromatron中的各种光学元件</p></div>
<p>别的关卡都可以不谈，但有一关是一定要说一下的，这一关太有趣了。虽然它也有传统的解法，但其中有一种解法却非常神奇。见下图：</p>
<div id="attachment_1652" class="wp-caption alignnone" style="width: 389px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2012/02/chromatron_2_49.png" alt="chromatron_2_49" title="chromatron_2_49" width="379" height="394" class="size-full wp-image-1652 wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">Chromatron 2代49关：反馈消除</p></div>
<p>注意到那几个没有光线经过的反射镜了吗？看起来它们摆在那儿是多余的，但一旦移动它们，你就输了。游戏中对这一关的说明是：</p>
<blockquote>
<p>If the complementor is presented with a logical impossibility, it shuts down in all directions.</p>
</blockquote>
<p>想亲自尝试一下？赶紧通过上面的链接下载下来玩吧。</p>
<p>最后放上我的各关解法，需要的可以参考之。用的时候，找到你要解决的关卡（比如3代第9关），复制对应的解法代码（如3-09-nIIAnqNtOvNPtNsJOx），注意复制的时候要包括开头的3-09-，而代码首尾都不要包含任何其他字符（如空格、回车等）。在游戏中进入此关卡，按Ctrl-V即可。如果你要向别人分享你的解法，就可以在游戏中进入关卡，按Ctrl-C，然后在任何文本编辑器中按Ctrl-V粘贴。</p>
<div id="wp-tabs-1" class="wp-tabs wpui-light wpui-styles"><h3 class="wp-tab-title">Chromatron 1代 v1.14</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">1-01-hI<br />
1-02-hXioDr<br />
1-03-nJtNcl<br />
1-04-rODFCJ<br />
1-05-ibOmsU<br />
1-06-hvhThWhs<br />
1-07-ortYCq<br />
1-08-iUczmB<br />
1-09-HHmrpfHjyZmP<br />
1-10-ilCSNZbNCAbWIZOADOaDcxyTiDtKoqjjzKuBpk<br />
1-11-oEcQOyyq<br />
1-12-DathEiOn<br />
1-13-JpNKxtbLHniczJJDyx<br />
1-14-sasWOjsRIkdcbG<br />
1-15-HWoItJhNHAcgJCIthCsB<br />
1-16-ntbgIJINrisKnxNjnbcM<br />
1-17-JfIvCKmTchcNINNKsCEhioOB<br />
1-18-NjcAtyiFCddq<br />
1-19-CZOOrZ<br />
1-20-dmClHANHySoeawIg<br />
1-21-ObsunsMFxA<br />
1-22-caiVoeaOKeFpbKDebE<br />
1-23-cnHFIjynclHbcpoDypnZphOyOi<br />
1-24-bJNtmNHrOyCouoPumRrK<br />
1-25-hBDIoWdKoeHOQKEP<br />
1-26-hZDPcznv<br />
1-27-MHjPuzGUAcIVph<br />
1-28-uKjOMVQrzPaxavco<br />
1-29-mUbqlGoAyYyUImocxicl<br />
1-30-onJDnZHbye<br />
1-31-bZHrovbphiNg<br />
1-32-BMjktMJdzzCsOS<br />
1-33-OBDzOnsYsHOEysevDknZtNiRLodrikeG<br />
1-34-cpbfCqOBgz<br />
1-35-azBKzwCWaqIIDCiSFuAnHl<br />
1-36-Fpcnyajzgz<br />
1-37-xlhKdbDA<br />
1-38-hZsKPYOEtVDLNywTMADx<br />
1-39-hxEbOVuljjNjoSCbDNfVxggVxKosnIPjczxryFgO<br />
1-40-ernOODhZ<br />
1-41-IDtyxV<br />
1-42-tHBTgBOBiNjQiLFpgxOv<br />
1-43-HboDmHGXxJdhoHwBOe<br />
1-44-gMgqCeOMDMtYulMVdCyT<br />
1-45-EwbauFwHilxwhgdepkdaNd<br />
1-46-hNCIbwNzIRHTnytMjQhu<br />
1-47-coBvxonWDnbUfVaoOLaSuzKuFpympo<br />
1-48-sUjtcnzJuEsYNY<br />
1-49-DwMGMKrsgEBHhNtGdtdnng<br />
1-50-CbNiHScQhwxKoEzwDVCZhTwJxM</div></div></div></div><!-- end div.wp-tab-content --></pre>
<h3 class="wp-tab-title">Chromatron 2代 v1.5</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">2-01-BRgqgZhjqZ<br />
2-02-mDGXzupcMGJagFoXNowP<br />
2-03-coOEOBOy<br />
2-04-OIBOixHtovzwIjqTJnFd<br />
2-05-NYCrtYIJnrxw<br />
2-06-tGiPDLccFMes<br />
2-07-hLIyng<br />
2-08-hLIyni<br />
2-09-hxCbMFFMtIBMhs<br />
2-10-QurbNejIBwuxwm<br />
2-11-MRxubKyCirupoUHo<br />
2-12-DAyiOD<br />
2-13-izoVhgCUNgyKHTDOuCbD<br />
2-14-cnoDMP<br />
2-15-MAOCimBv<br />
2-16-NUrUopHNDOgOOezxoP<br />
2-17-bZCGxNxUgiINLl<br />
2-18-hLHUIjci<br />
2-19-oRynHThKOmyTPG<br />
2-20-nwrMySNXbuOl<br />
2-21-hbhfifirjrfP<br />
2-22-cmhCHUxIpiootwHHjQIIgSMNjvihsP<br />
2-23-tJjcIwygDBsBhH<br />
2-24-CGimHIxONJ<br />
2-25-skMzBEMHwPgycXBwhzPkEpOlIOEtzRjzpe<br />
2-26-twPYiBnmHGzvMGnh<br />
2-27-tvNLCHoGxkye<br />
2-28-sDytMHwluzGVebpnHhgcpbbRFi<br />
2-29-clckDDcj<br />
2-30-nkgDIgbpmqDzclaXJRcYPuocdtdU<br />
2-31-sJxihFELtJNxiTfV<br />
2-32-wRHnNNjliUsEIhnbdxNU<br />
2-33-szsNtgFMbEIcHCmMJo<br />
2-34-jPMNBKuEilIGIcJOKslCnoyG<br />
2-35-oQNcxvcCyCMRoUHk<br />
2-36-yEMFCUpiBvjObEQrcouLxUKQ<br />
2-37-yUbuomwCcCGYhHhv<br />
2-38-OCBzMBBHeruLCuNAmqsCMvesiBtGjDzYolwIikaoJS<br />
2-39-eserbLCSbCIybT<br />
2-40-hxsTnaNdOnDD<br />
2-41-tsMUIcIeNMNOcMHktCoeEKdGukumoY<br />
2-42-sZDkiOMUtfzhJFIocw<br />
2-43-cwwAaIHLbhxIxRGWdxKBpluGdUty<br />
2-44-HWNNIdNxIINUIwersRnbyhhNntDxImsp<br />
2-45-NxiEOnDhtvCozvKfjgziICJgFM<br />
2-46-rXtwAngxbagKbCCyHT<br />
2-47-hsuHDhyGETNXbS<br />
2-48-hIwQHFerNyjjzwCvIzdBdExaJLpvHV<br />
2-49-yDaCritKcoHrusoqKzjzhCJc<br />
2-50-OtMzBDBwNdCsNurGuGjHtvjJQKPYubIIochxDhNLsPcCCbym</div></div></div></div><!-- end div.wp-tab-content --></pre>
<h3 class="wp-tab-title">Chromatron 3代 v1.1</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">3-01-oCcmcO<br />
3-02-JeHgwAgrMvETdMuBuL<br />
3-03-gOCggnjMBFOSyZdJCGsU<br />
3-04-omoZINqLBA<br />
3-05-bWhYuOsUyGnKOANZ<br />
3-06-oSgPOEHqyUiDbsCH<br />
3-07-HTxZclzhontQHP<br />
3-08-IyDlnJcAnMIwsRcjyreAeB<br />
3-09-nIIAnqNtOvNPtNsJOx<br />
3-10-ynHFHJxfbvHBcDnVnZuG<br />
3-11-ILnubXIOnxOIsHDyOzsEOCtG<br />
3-12-NtaShFCqMFaQIwtjjijP<br />
3-13-NLCWhNergM<br />
3-14-ORbesbzmHFDRmEHIhMoEoG<br />
3-15-yeMvcoxeImmMoSPQyEjPtRNrgfhF<br />
3-16-sFMVrrgzCTNXBLhJEfiruljr<br />
3-17-DwhODD<br />
3-18-xDMTBNjxunbBbfCqxZhMMPPJiLNxPNrxjtCrsF<br />
3-19-ikgShbhJjqjjjDiWhzlYntiE<br />
3-20-ulhNDxoSMP<br />
3-21-yWIQnAuGITEZjfnljJca<br />
3-22-DCsUhIOmDD<br />
3-23-tINyjioIzwaQHAng<br />
3-24-OeHsHWburUBGxMbYniyIoajMbI<br />
3-25-sBNrCwNzOvhIsLtHiNduCr<br />
3-26-sFBLCbNjxXphHbtXjluljycp<br />
3-27-bvnZHqHtxYeroPyRMwsLwPBZIOKxjdGWhu<br />
3-28-HGbYOdhNMNxtDliHoQs<br />
3-29-CpMRpcbgsznxaiBw<br />
3-30-szMJCJNJbKIJiABKtwnyneDSxQJdtchrcv<br />
3-31-teCGNPDEOGCbistNiUtYjf<br />
3-32-bKHswSoQHocSihoUyCbAIs<br />
3-33-CdNhtZphHbjhyDCUcpOE<br />
3-34-DJpidIxOhBOCirOVhXtosXIdsCaOCdDR<br />
3-35-NxtdoWHOFe<br />
3-36-wAGWIMNZnZHNJfNlniovtVoGjz<br />
3-37-erjtMVupirPdtdBLyrssPjshtfCXMRrXNRqTNXPf<br />
3-38-DPaOCWbHCdcAtKiSdq<br />
3-39-OwDHrXbVyHiqMUGXtIplxB<br />
3-40-ewtOrqCZOaDwMTOyDEhLBQidtuizsXPQtZjeeuNp<br />
3-41-MRBNBxjGNHuBuvPjCWnwyCbREybLrJhDxO<br />
3-42-KRwlHrwPaVxbxtGXbBbLydGVctJDyRdxoFcpebpfpjplpn<br />
3-43-mqciyuKuoDNf<br />
3-44-tGBKiWuAhNMPCbtXurjzDxMV<br />
3-45-DNcaulxjNOhvtkpgtaiscEHICTMzoUBx<br />
3-46-PyBKaCbfDhbZMzoCzBjkuzzZjO<br />
3-47-sJspinOzHTbXtjNuckEw<br />
3-48-uECVirMYMDMWNyCDNKMKNiCtMxOdtsiFtKiRtYjiukjAtejL<br />
3-49-BPMTIeIkxIoWnGtwiEdisD<br />
3-50-OnNlCrNyCICbioCWtYDnjijWiUtwtIiChgNKCNixtiesEiey</div></div></div></div><!-- end div.wp-tab-content --></pre>
<h3 class="wp-tab-title">Chromatron 4代 v1.0</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">4-01-OqHQhHOi<br />
4-02-OHDxoYCboSHbci<br />
4-03-tZGYsVyb<br />
4-04-wSHIbeHCxA<br />
4-05-xZcDjwuGPYiSaL<br />
4-06-xlEUbLcoHqFjQtmD<br />
4-07-JGIyOmDSCKtyjeNe<br />
4-08-EECqbeaPiTzvjiCb<br />
4-09-NLOGsA<br />
4-10-DzuKhWGUzYuCHwoNjP<br />
4-11-bzqNaAHNBvxZcttfjQ<br />
4-12-iTzizm<br />
4-13-omxIgMjNMNrfCFPf<br />
4-14-EuMHNaCygGhGBBPAtQiVtYjc<br />
4-15-cAtXGWgxcwOnyY<br />
4-16-CgiRaQFpINaPHH<br />
4-17-MxHetHAniWJlgVsnImzKjsAgOX<br />
4-18-tZycopjhbhCudEKz<br />
4-19-DzdqhLwWckcicg<br />
4-20-MwCSMEEqhSsNrxHebKBwsJjAzTdhcXzbbAbebIaH<br />
4-21-cgaBNbbebmNOaqJCcOPUdHdOea<br />
4-22-xibtDkssqFIj<br />
4-23-CDugPmMLclcf<br />
4-24-EmCjaSxIuBBZhzaIpmcMbQOp<br />
4-25-jPiRsFDUtGPmJFuEichGumJzHPHF<br />
4-26-hENUIMCUttOsnwsXnztaIOJd<br />
4-27-CJCcrtyTHqgRbgoRpcaP<br />
4-28-tiBLaDHTamySiGjjjQ<br />
4-29-BRNK<br />
4-30-rUrPPtCf<br />
4-31-COjlMyNPHPHFMGmVmPsqirJoOROUuBtOtRudCwJWNc<br />
4-32-HFmkbHHcddyVoDhzxL<br />
4-33-iWtGHZuIbLHyssjNGXNvtfKIoNbHdsbGdncMer<br />
4-34-jwcluoCDDA<br />
4-35-GZwQwRGYbHcSoGoHmE<br />
4-36-QLxlCWbEyqovMWzjQKiStwKkcx<br />
4-37-hyNkbuniDkCduKMB<br />
4-38-IjOxsGnWjIBz<br />
4-39-MLHqxwcEiVqMyEcQEntLtjurer<br />
4-40-ndbvng<br />
4-41-DjMwnfNFnXjDnZHtNEJBtglNsm<br />
4-42-bWeserNKtghqCeinhMIKJeJGNFbagp<br />
4-43-NyCsxMBPbWiopmEhgz<br />
4-44-BymdtBjMyHFcNp<br />
4-45-iobIyECWIMchiihg<br />
4-46-uDCotJaOCbHnGVHmbdiWzvjltHjP<br />
4-47-tQNwxXiWCvwXcdci<br />
4-48-nLMVriNgCtIkIRcCBKcTyUtYjgjkoSjG<br />
4-49-BEssOXjClPmBCjsjJlMzhzENiVdEoRDVeser<br />
4-50-BCMCcCHODwNHNOuaFpGZjhnGEbIRrKzadshHsHne</div></div></div></div><!-- end div.wp-tab-content --></div><!-- end div.wp-tabs --></pre>
<p>如果没玩过这个游戏，那就赶快开始吧！</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/chromatron.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>iPhone开发：自定义控件RangeSlider（范围滑动条）</title>
		<link>http://www.gocalf.com/blog/iphone-dev-range-slider.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=iphone-dev-range-slider</link>
		<comments>http://www.gocalf.com/blog/iphone-dev-range-slider.html#comments</comments>
		<pubDate>Fri, 03 Feb 2012 13:19:44 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[程序开发]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPhone 开发]]></category>
		<category><![CDATA[ObjC]]></category>
		<category><![CDATA[Range Slider]]></category>
		<category><![CDATA[UIControl]]></category>
		<category><![CDATA[UISlider]]></category>
		<category><![CDATA[控件]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1602</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/02/range_slider_icon.png" class="attachment-post-thumbnail wp-post-image" alt="range_slider_icon" title="range_slider_icon" /></div>前些日子写app的时候遇到一个需求，希望有一个类似于UISlider的东西，但能够选取一个范围，也就是所谓的Range Slider。在网上也能找到很多相关的代码，不过本着学习的态度，还是自己琢磨了一下。

就当是为以后写复杂控件做的练习吧。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2012/02/range_slider_icon.png" class="attachment-post-thumbnail wp-post-image" alt="range_slider_icon" title="range_slider_icon" /></div><p>前些日子写app的时候遇到一个需求，希望有一个类似于<a href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UISlider_Class/Reference/Reference.html" target="_blank">UISlider</a>的东西，但能够选取一个范围，也就是所谓的Range Slider。在网上也能找到很多相关的代码，不过本着学习的态度，还是自己琢磨了一下。</p>
<p>就当是为以后写复杂控件做的练习吧。<span id="more-1602"></span></p>
<p>以下内容适用于iOS 2.0+。</p>
<p>需求决定一切，在介绍我的这个Range Slider之前，先把我的需求（或者说我这个Range Slider的功能）介绍一下。它最多只算是个toy，还有很多需要完善的地方。不过聊胜于无，以后继续努力呗。</p>
<p>这是一个水平方向的（浮点）数值范围选择器：</p>
<ul>
<li>可以为它设置数值的最小值（minimumValue）和最大值（maximumValue），分别对应于滑动条最左端和最右端的数值。</li>
<li>可以设置范围的最小值（minimumSpan）和最大值（maximumSpan），因为我可能会要求选择的数值区间长度不太短或不太长。</li>
<li>可以获取或设置当前选择的数值范围（smallValue和largeValue），对应于界面上左右两个滑块的位置。</li>
<li>左右两个滑块都可以相互独立地左右滑动；一个滑块滑动时，另一个滑块会根据需要自动调整。比如当向左滑动左边的滑块时，如果选取的范围已经达到范围最大值（maximumSpan），右边的滑块就会跟着向左滑动。反之亦然。</li>
<li>两个滑块中间的条块也是可以滑动的，移动它的时候，两个滑块会一起左右移动（不改变选取范围的长度）。</li>
<li>当滑块或者滑条移动时，此控件的UIControlEventValueChanged事件会被触发。</li>
<li>可以用程序修改当前的选择范围，UI会跟着调整，但不会触发上述事件，以免在某些情况下陷入死循环。</li>
<li>以左滑块为例，当它滑动到最左边后，如果手指继续做向左滑动的动作，当前选择的范围不会变化，但会通过另一个量（offsetTrend）来表达这种趋势。在某些情况下，应用程序可能会需要得到这样的信息，以便当用户在slider边缘继续往外滑动时，进行一些特殊的处理。右滑块和滑条都有同样的功能。</li>
<li>可以为这个控件设置委托（delegate），当滑块或者滑条将要开始滑动、或者滑动结束的时候，委托的对象都会收到相应的消息。当然，会有一个只读的量（isDragging）用来查询是否有滑块或者滑条在滑动中。</li>
<li>slider的背景条、滑块、滑条的图案都可以被替换。</li>
</ul>
<p>我的这个Range Slider暂<strong>不支持</strong>的功能包括但不限于：</p>
<ul>
<li>不支持纵向的滑动模式（或许可以直接利用旋转整个控件达到此目的）。</li>
<li>没有为自定义UI样式提供足够的接口。虽然背景和滑块的图片都能替换，但并不支持为每一个对象实例单独替换图片。比起SDK中的UISlider，这方面的功能是相当薄弱的。</li>
</ul>
<p>说了这么多，来看看它的样子吧。外表很简单，我用的背景、滑块和滑条图片都跟UISlider是一样的：</p>
<div id="attachment_1609" class="wp-caption alignnone" style="width: 330px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2012/02/range_slider.png" alt="range_slider" title="range_slider" width="320" height="67" class="size-full wp-image-1609 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">我的Range Slider</p></div>
<p>实现起来蛮简单的，因为SDK已经提供了足够的支持。我的这个类就叫做RangeSlider，继承自<a href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UIControl_Class/Reference/Reference.html#//apple_ref/occ/cl/UIControl" target="_blank">UIControl</a>类。另外我还定义了它的委托类，叫做RangeSliderDelegate。二者的接口如下：</p>
<div id="wp-tabs-2" class="wp-tabs wpui-light wpui-styles"><h3 class="wp-tab-title">RangeSlider</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #6e371a;">#import &lt;UIKit/UIKit.h&gt;</span><br />
<br />
<span style="color: #a61390;">@protocol</span> RangeSliderDelegate;<br />
<br />
<span style="color: #a61390;">@interface</span> RangeSlider <span style="color: #002200;">:</span> UIControl <span style="color: #002200;">&#123;</span><br />
<span style="color: #a61390;">@private</span><br />
&nbsp; &nbsp; id&lt;RangeSliderDelegate&gt; delegate_;<br />
<br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> minimumValue_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> maximumValue_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> minimumSpan_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> maximumSpan_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> smallValue_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> largeValue_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> offsetTrend_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">int</span> insetWidthLeft_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">int</span> rangeWidth_;<br />
<br />
&nbsp; &nbsp; UIImageView<span style="color: #002200;">*</span> selectionView_;<br />
&nbsp; &nbsp; UIImageView<span style="color: #002200;">*</span> smallHandle_;<br />
&nbsp; &nbsp; UIImageView<span style="color: #002200;">*</span> largeHandle_;<br />
<br />
&nbsp; &nbsp; <span style="color: #a61390;">BOOL</span> isTrackingSmallHandle_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">BOOL</span> isTrackingLargeHandle_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">BOOL</span> isTrackingSelection_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">BOOL</span> isDragging_;<br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #11740a; font-style: italic;">// The delegate object.</span><br />
<span style="color: #a61390;">@property</span><span style="color: #002200;">&#40;</span>nonatomic, assign<span style="color: #002200;">&#41;</span> id&lt;RangeSliderDelegate&gt; delegate;<br />
<br />
<span style="color: #11740a; font-style: italic;">// The minimum value of the slider.</span><br />
<span style="color: #11740a; font-style: italic;">// The default value is 0.0.</span><br />
<span style="color: #a61390;">@property</span><span style="color: #002200;">&#40;</span>nonatomic, assign<span style="color: #002200;">&#41;</span> <span style="color: #a61390;">float</span> minimumValue;<br />
<br />
<span style="color: #11740a; font-style: italic;">// The maximum value of the slider.</span><br />
<span style="color: #11740a; font-style: italic;">// The default value is 1.0.</span><br />
<span style="color: #a61390;">@property</span><span style="color: #002200;">&#40;</span>nonatomic, assign<span style="color: #002200;">&#41;</span> <span style="color: #a61390;">float</span> maximumValue;<br />
<br />
<span style="color: #11740a; font-style: italic;">// The minimum span of the selected range.</span><br />
<span style="color: #11740a; font-style: italic;">// The default value is 0.1.</span><br />
<span style="color: #a61390;">@property</span><span style="color: #002200;">&#40;</span>nonatomic, assign<span style="color: #002200;">&#41;</span> <span style="color: #a61390;">float</span> minimumSpan;<br />
<br />
<span style="color: #11740a; font-style: italic;">// The maximum span of the selected range.</span><br />
<span style="color: #11740a; font-style: italic;">// The default value is 1.0.</span><br />
<span style="color: #a61390;">@property</span><span style="color: #002200;">&#40;</span>nonatomic, assign<span style="color: #002200;">&#41;</span> <span style="color: #a61390;">float</span> maximumSpan;<br />
<br />
<span style="color: #11740a; font-style: italic;">// The lower bound of the selected range.</span><br />
<span style="color: #a61390;">@property</span><span style="color: #002200;">&#40;</span>nonatomic, assign, setter<span style="color: #002200;">=</span>setSmallValue<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">float</span> smallValue;<br />
<br />
<span style="color: #11740a; font-style: italic;">// The higher bound of the selected range.</span><br />
<span style="color: #a61390;">@property</span><span style="color: #002200;">&#40;</span>nonatomic, assign, setter<span style="color: #002200;">=</span>setLargeValue<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">float</span> largeValue;<br />
<br />
<span style="color: #11740a; font-style: italic;">// A Boolean value that indicates whether the user has begun dragging.</span><br />
<span style="color: #a61390;">@property</span><span style="color: #002200;">&#40;</span>nonatomic, assign, readonly<span style="color: #002200;">&#41;</span> <span style="color: #a61390;">BOOL</span> isDragging;<br />
<br />
<span style="color: #11740a; font-style: italic;">// Initialization with frame, also specify the inset of left and right edge.</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithFrame<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGRect<span style="color: #002200;">&#41;</span>frame insetLeft<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">int</span><span style="color: #002200;">&#41;</span>insetLeft insetRight<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">int</span><span style="color: #002200;">&#41;</span>insetRight;<br />
<br />
<span style="color: #11740a; font-style: italic;">// Move the current selection.</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>moveSelection<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>offset;<br />
<br />
<span style="color: #11740a; font-style: italic;">// Gets offset trend, it will be reset to 0 after call finished.</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>getAndResetOffsetTrend;<br />
<br />
<span style="color: #11740a; font-style: italic;">// Converts slider value to x coor.</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>xForValue<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>value;<br />
<br />
<span style="color: #11740a; font-style: italic;">// Converts x coor to slider value.</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>valueForX<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>x;<br />
<br />
<span style="color: #a61390;">@end</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<h3 class="wp-tab-title">RangeSliderDelegate</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #a61390;">@protocol</span> RangeSliderDelegate&lt;NSObject&gt;<br />
@optional<br />
<br />
<span style="color: #11740a; font-style: italic;">// Tells the delegate when the slider is about to start dragging.</span><br />
<span style="color: #11740a; font-style: italic;">// The delegate might not receive this message until dragging has occurred over a small distance.</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>rangeSliderWillBeginDragging<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>RangeSlider<span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>rangeSlider;<br />
<br />
<span style="color: #11740a; font-style: italic;">// Tells the delegate when dragging ended in the range slider.</span><br />
<span style="color: #11740a; font-style: italic;">// This message is sent when the user's finger touches up after dragging.</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>rangeSliderDidEndDragging<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>RangeSlider<span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>rangeSlider;<br />
<br />
<span style="color: #a61390;">@end</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></div><!-- end div.wp-tabs --></pre>
<p>接口中的大部分内容都在需求和功能介绍部分见过了。另外有两个方法，xForValue和valueForX，它们用来在Range Slider内部的坐标值和用户数值之间做转换，内容如下（这里的insetWidth是在UI上做的小伎俩，主要是为了保证滑块滑到最两端时也能有充足的空间来接受用户的点击）：</p>
<pre><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>xForValue<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>value <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">return</span> insetWidthLeft_ <span style="color: #002200;">+</span> rangeWidth_ <span style="color: #002200;">*</span> <span style="color: #002200;">&#40;</span>value <span style="color: #002200;">-</span> minimumValue_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">/</span> <span style="color: #002200;">&#40;</span>maximumValue_ <span style="color: #002200;">-</span> minimumValue_<span style="color: #002200;">&#41;</span>;<br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>valueForX<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>x <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">return</span> minimumValue_ <span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span>x <span style="color: #002200;">-</span> insetWidthLeft_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">*</span> <span style="color: #002200;">&#40;</span>maximumValue_ <span style="color: #002200;">-</span> minimumValue_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">/</span> rangeWidth_;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></pre>
<p>我就不贴完整的.m源文件了，只是逐个介绍一下重要的方法。</p>
<p>首先看初始化方法initWithFrame，和更新显示的方法updateSelectionView。这个没啥好说的，就是初始化成员变量，创建好相关的图片：</p>
<div id="wp-tabs-3" class="wp-tabs wpui-light wpui-styles"><h3 class="wp-tab-title">initWithFrame</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithFrame<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGRect<span style="color: #002200;">&#41;</span>frame insetLeft<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">int</span><span style="color: #002200;">&#41;</span>insetLeft insetRight<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">int</span><span style="color: #002200;">&#41;</span>insetRight <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; self <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>super initWithFrame<span style="color: #002200;">:</span>frame<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>self <span style="color: #002200;">!=</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Set the initial state.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; minimumValue_ <span style="color: #002200;">=</span> 0.0f;<br />
&nbsp; &nbsp; &nbsp; &nbsp; maximumValue_ <span style="color: #002200;">=</span> 1.0f;<br />
&nbsp; &nbsp; &nbsp; &nbsp; minimumSpan_ <span style="color: #002200;">=</span> 0.1f;<br />
&nbsp; &nbsp; &nbsp; &nbsp; maximumSpan_ <span style="color: #002200;">=</span> 0.7f;<br />
&nbsp; &nbsp; &nbsp; &nbsp; smallValue_ <span style="color: #002200;">=</span> minimumValue_;<br />
&nbsp; &nbsp; &nbsp; &nbsp; largeValue_ <span style="color: #002200;">=</span> minimumValue_ <span style="color: #002200;">+</span> maximumSpan_;<br />
&nbsp; &nbsp; &nbsp; &nbsp; offsetTrend_ <span style="color: #002200;">=</span> 0.0f;<br />
&nbsp; &nbsp; &nbsp; &nbsp; insetWidthLeft_ <span style="color: #002200;">=</span> insetLeft;<br />
&nbsp; &nbsp; &nbsp; &nbsp; rangeWidth_ <span style="color: #002200;">=</span> frame.size.width <span style="color: #002200;">-</span> insetLeft <span style="color: #002200;">-</span> insetRight;<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; isTrackingSmallHandle_ <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; isTrackingLargeHandle_ <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; isTrackingSelection_ <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; isDragging_ <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">float</span> centerY <span style="color: #002200;">=</span> frame.size.height <span style="color: #002200;">/</span> 2.0f;<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Background image.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; UIImageView<span style="color: #002200;">*</span> background <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIImageView alloc<span style="color: #002200;">&#93;</span> initWithImage<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>UIImage imageNamed<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;rangeslider-bg.png&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; autorelease<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; background.frame <span style="color: #002200;">=</span> CGRectMake<span style="color: #002200;">&#40;</span>insetWidthLeft_, <span style="color: #2400d9;">0</span>, rangeWidth_, background.frame.size.height<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; background.center <span style="color: #002200;">=</span> CGPointMake<span style="color: #002200;">&#40;</span>background.center.x, centerY<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self addSubview<span style="color: #002200;">:</span>background<span style="color: #002200;">&#93;</span>;<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Selection image.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; selectionView_ <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIImageView alloc<span style="color: #002200;">&#93;</span> initWithImage<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>UIImage imageNamed<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;rangeslider-select.png&quot;</span><span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; highlightedImage<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>UIImage imageNamed<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;rangeslider-select-hover.png&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; autorelease<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; selectionView_.center <span style="color: #002200;">=</span> CGPointMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">0</span>, centerY<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self addSubview<span style="color: #002200;">:</span>selectionView_<span style="color: #002200;">&#93;</span>;<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Left handle for small value selection.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; smallHandle_ <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIImageView alloc<span style="color: #002200;">&#93;</span> initWithImage<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>UIImage imageNamed<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;rangeslider-handle.png&quot;</span><span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; highlightedImage<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>UIImage imageNamed<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;rangeslider-handle-hover.png&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; autorelease<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; smallHandle_.center <span style="color: #002200;">=</span> CGPointMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">0</span>, centerY<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self addSubview<span style="color: #002200;">:</span>smallHandle_<span style="color: #002200;">&#93;</span>;<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Right handle for small value selection.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; largeHandle_ <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIImageView alloc<span style="color: #002200;">&#93;</span> initWithImage<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>UIImage imageNamed<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;rangeslider-handle.png&quot;</span><span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; highlightedImage<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>UIImage imageNamed<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;rangeslider-handle-hover.png&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; autorelease<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; largeHandle_.center <span style="color: #002200;">=</span> CGPointMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">0</span>, centerY<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self addSubview<span style="color: #002200;">:</span>largeHandle_<span style="color: #002200;">&#93;</span>;<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self updateSelectionView<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #a61390;">return</span> self;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<h3 class="wp-tab-title">updateSelectionView</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>updateSelectionView <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; smallHandle_.center <span style="color: #002200;">=</span> CGPointMake<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>self xForValue<span style="color: #002200;">:</span>smallValue_<span style="color: #002200;">&#93;</span>, smallHandle_.center.y<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; largeHandle_.center <span style="color: #002200;">=</span> CGPointMake<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>self xForValue<span style="color: #002200;">:</span>largeValue_<span style="color: #002200;">&#93;</span>, largeHandle_.center.y<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; selectionView_.frame <span style="color: #002200;">=</span> CGRectMake<span style="color: #002200;">&#40;</span>smallHandle_.center.x,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; selectionView_.frame.origin.y,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; largeHandle_.center.x <span style="color: #002200;">-</span> smallHandle_.center.x,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; selectionView_.frame.size.height<span style="color: #002200;">&#41;</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></div><!-- end div.wp-tabs --></pre>
<p>接下来看最重要的部分，就是处理触摸事件的方法。这些方法继承自基类UIControl，分别是<a href="http://developer.apple.com/library/ios/documentation/uikit/reference/UIControl_Class/Reference/Reference.html#//apple_ref/occ/instm/UIControl/beginTrackingWithTouch:withEvent:" target="_blank">beginTrackingWithTouch:withEvent:</a>，<a href="http://developer.apple.com/library/ios/documentation/uikit/reference/UIControl_Class/Reference/Reference.html#//apple_ref/occ/instm/UIControl/continueTrackingWithTouch:withEvent:" target="_blank">continueTrackingWithTouch:withEvent:</a>，和<a href="http://developer.apple.com/library/ios/documentation/uikit/reference/UIControl_Class/Reference/Reference.html#//apple_ref/occ/instm/UIControl/endTrackingWithTouch:withEvent:" target="_blank">endTrackingWithTouch:withEvent:</a>。</p>
<p>beginTracking和endTracking都很简单，在beginTracking的时候判断是哪个东西被拖动，让其进入高亮状态，修改成员变量记录当前的状态；在endTracking的时候取消高亮，恢复状态。</p>
<p>在continueTracking方法中，先获取手指移动的坐标偏移量，将其换算成数值的偏移量，然后就直接调用相应的设置函数修改已选择的数值区域。</p>
<p>注意rangeSliderWillBeginDragging和rangeSliderDidEndDragging这两个消息的回调时机。手指刚刚按在滑块上的时候，beginTracking被调用，但这时并不表示用户开始已经开始拖动了，他可能只是按了一下，马上就抬起来。所以当手指按住滑块并有了第一次微小的位移时，continueTracking被调用，这时就可以确定用户是在进行拖动操作。这时候才发送rangeSliderWillBeginDragging消息。最后当手指离开滑块时，拖动操作结束，发送rangeSliderDidEndDragging消息。</p>
<div id="wp-tabs-4" class="wp-tabs wpui-light wpui-styles"><h3 class="wp-tab-title">beginTrackingWithTouch</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>beginTrackingWithTouch<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>UITouch<span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>touch withEvent<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>UIEvent<span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>event <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; CGPoint touchPoint <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>touch locationInView<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>CGRectContainsPoint<span style="color: #002200;">&#40;</span>largeHandle_.frame, touchPoint<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; largeHandle_.highlighted <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; isTrackingLargeHandle_ <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">else</span> <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>CGRectContainsPoint<span style="color: #002200;">&#40;</span>smallHandle_.frame, touchPoint<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; smallHandle_.highlighted <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; isTrackingSmallHandle_ <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">else</span> <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>CGRectContainsPoint<span style="color: #002200;">&#40;</span>selectionView_.frame, touchPoint<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; selectionView_.highlighted <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; isTrackingSelection_ <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">else</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">return</span> <span style="color: #a61390;">NO</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<br />
&nbsp; &nbsp; isDragging_ <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">return</span> <span style="color: #a61390;">YES</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<h3 class="wp-tab-title">continueTrackingWithTouch</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>continueTrackingWithTouch<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>UITouch<span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>touch withEvent<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>UIEvent<span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>event <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span>isTrackingSmallHandle_ <span style="color: #002200;">&amp;&amp;</span> <span style="color: #002200;">!</span>isTrackingLargeHandle_ <span style="color: #002200;">&amp;&amp;</span> <span style="color: #002200;">!</span>isTrackingSelection_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">return</span> <span style="color: #a61390;">NO</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span>isDragging_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; isDragging_ <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>self.delegate respondsToSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>rangeSliderWillBeginDragging<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self.delegate rangeSliderWillBeginDragging<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> prev <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self valueForX<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>touch previousLocationInView<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>.x<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> curr <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self valueForX<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>touch locationInView<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>.x<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> offset <span style="color: #002200;">=</span> curr <span style="color: #002200;">-</span> prev;<br />
<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>isTrackingSmallHandle_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; self.smallValue <span style="color: #002200;">=</span> smallValue_ <span style="color: #002200;">+</span> offset;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">else</span> <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>isTrackingLargeHandle_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; self.largeValue <span style="color: #002200;">=</span> largeValue_ <span style="color: #002200;">+</span> offset;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">else</span> <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>isTrackingSelection_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self moveSelection<span style="color: #002200;">:</span>offset<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self sendActionsForControlEvents<span style="color: #002200;">:</span>UIControlEventValueChanged<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">return</span> <span style="color: #a61390;">YES</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<h3 class="wp-tab-title">endTrackingWithTouch</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>endTrackingWithTouch<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>UITouch<span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>touch withEvent<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>UIEvent<span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>event <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; isTrackingSmallHandle_ <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
&nbsp; &nbsp; isTrackingLargeHandle_ <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
&nbsp; &nbsp; isTrackingSelection_ <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
<br />
&nbsp; &nbsp; selectionView_.highlighted <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
&nbsp; &nbsp; smallHandle_.highlighted <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
&nbsp; &nbsp; largeHandle_.highlighted <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>isDragging_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; isDragging_ <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>self.delegate respondsToSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>rangeSliderDidEndDragging<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self.delegate rangeSliderDidEndDragging<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></div><!-- end div.wp-tabs --></pre>
<p>最后就是修改smallValue、largeValue和整个选取范围的方法，这些方法会在滑动过程中由上面的continueTrackingWithTouch:withEvent:调用，也可以由其他程序直接调用。</p>
<p>不但要保证smallValue和largeValue都在最小值和最大值范围之内，还要根据最小范围和最大范围的限制来进行适当的调整。</p>
<div id="wp-tabs-5" class="wp-tabs wpui-light wpui-styles"><h3 class="wp-tab-title">setSmallValue</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setSmallValue<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>value <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; smallValue_ <span style="color: #002200;">=</span> value;<br />
<br />
&nbsp; &nbsp; smallValue_ <span style="color: #002200;">=</span> MIN<span style="color: #002200;">&#40;</span>MAX<span style="color: #002200;">&#40;</span>smallValue_, minimumValue_<span style="color: #002200;">&#41;</span>, maximumValue_ <span style="color: #002200;">-</span> minimumSpan_<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>smallValue_ &lt; largeValue_ <span style="color: #002200;">-</span> maximumSpan_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; largeValue_ <span style="color: #002200;">=</span> smallValue_ <span style="color: #002200;">+</span> maximumSpan_;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">else</span> <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>smallValue_ &gt; largeValue_ <span style="color: #002200;">-</span> minimumSpan_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; largeValue_ <span style="color: #002200;">=</span> smallValue_ <span style="color: #002200;">+</span> minimumSpan_;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<br />
&nbsp; &nbsp; offsetTrend_ <span style="color: #002200;">=</span> value <span style="color: #002200;">-</span> smallValue_;<br />
<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self updateSelectionView<span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<h3 class="wp-tab-title">setLargeValue</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setLargeValue<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>value <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; largeValue_ <span style="color: #002200;">=</span> value;<br />
<br />
&nbsp; &nbsp; largeValue_ <span style="color: #002200;">=</span> MAX<span style="color: #002200;">&#40;</span>MIN<span style="color: #002200;">&#40;</span>largeValue_, maximumValue_<span style="color: #002200;">&#41;</span>, minimumValue_ <span style="color: #002200;">+</span> minimumSpan_<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>largeValue_ &lt; smallValue_ <span style="color: #002200;">+</span> minimumSpan_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; smallValue_ <span style="color: #002200;">=</span> largeValue_ <span style="color: #002200;">-</span> minimumSpan_;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>largeValue_ &gt; smallValue_ <span style="color: #002200;">+</span> maximumSpan_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; smallValue_ <span style="color: #002200;">=</span> largeValue_ <span style="color: #002200;">-</span> maximumSpan_;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<br />
&nbsp; &nbsp; offsetTrend_ <span style="color: #002200;">=</span> value <span style="color: #002200;">-</span> largeValue_;<br />
<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self updateSelectionView<span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<h3 class="wp-tab-title">moveSelection</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>moveSelection<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>offset <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> span <span style="color: #002200;">=</span> largeValue_ <span style="color: #002200;">-</span> smallValue_;<br />
&nbsp; &nbsp; <span style="color: #a61390;">float</span> prevSmallValue <span style="color: #002200;">=</span> smallValue_;<br />
&nbsp; &nbsp; smallValue_ <span style="color: #002200;">+=</span> offset;<br />
&nbsp; &nbsp; largeValue_ <span style="color: #002200;">+=</span> offset;<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>smallValue_ &lt; minimumValue_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; smallValue_ <span style="color: #002200;">=</span> minimumValue_;<br />
&nbsp; &nbsp; &nbsp; &nbsp; largeValue_ <span style="color: #002200;">=</span> smallValue_ <span style="color: #002200;">+</span> span;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">else</span> <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>largeValue_ &gt; maximumValue_<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; largeValue_ <span style="color: #002200;">=</span> maximumValue_;<br />
&nbsp; &nbsp; &nbsp; &nbsp; smallValue_ <span style="color: #002200;">=</span> largeValue_ <span style="color: #002200;">-</span> span;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<br />
&nbsp; &nbsp; offsetTrend_ <span style="color: #002200;">=</span> prevSmallValue <span style="color: #002200;">+</span> offset <span style="color: #002200;">-</span> smallValue_;<br />
<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self updateSelectionView<span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></div><!-- end div.wp-tabs --></pre>
<p>好了，基本上就这么些代码，还是很简单的。不放完整的程序文件了，只要了解了基本的处理方法，就可根据自己的需求去实现了。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/iphone-dev-progressview-in-alertview.html' rel='bookmark' title='iPhone开发：在UIAlertView中显示进度条'>iPhone开发：在UIAlertView中显示进度条</a></li>
<li><a href='http://www.gocalf.com/blog/iphone-dev-resizable-image.html' rel='bookmark' title='iPhone开发：可拉伸的图片'>iPhone开发：可拉伸的图片</a></li>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/iphone-dev-range-slider.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<series:name><![CDATA[iOS开发笔记]]></series:name>
	</item>
		<item>
		<title>条件概率：两个都是男孩的概率</title>
		<link>http://www.gocalf.com/blog/the-probability-of-two-boys.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=the-probability-of-two-boys</link>
		<comments>http://www.gocalf.com/blog/the-probability-of-two-boys.html#comments</comments>
		<pubDate>Fri, 30 Dec 2011 13:07:32 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[数学]]></category>
		<category><![CDATA[条件概率]]></category>
		<category><![CDATA[概率]]></category>
		<category><![CDATA[概率题]]></category>
		<category><![CDATA[贝叶斯公式]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1548</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/12/two_babies.png" class="attachment-post-thumbnail wp-post-image" alt="two_babies" title="two_babies" /></div>这个问题其实不难，只是很多时候，尤其在没有任何提示的时候，容易想错。条件概率的题目一定要看清楚条件信息。

问题描述：老王有两个孩子，已知至少有一个孩子是在星期二出生的男孩。问：两个孩子都是男孩的概率是多大？【假设生男生女的概率相等】]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/12/two_babies.png" class="attachment-post-thumbnail wp-post-image" alt="two_babies" title="two_babies" /></div><p>这个问题其实不难，只是很多时候，尤其在没有任何提示的时候，容易想错。条件概率的题目一定要看清楚条件信息。</p>
<p>问题描述：老王有两个孩子，已知至少有一个孩子是在星期二出生的男孩。问：两个孩子都是男孩的概率是多大？【假设生男生女的概率相等】<span id="more-1548"></span></p>
<p>刚看到题目的时候，我也愣了一下：一个孩子星期二出生，对于另一个孩子是不是男孩有什么影响吗？</p>
<p>先说一下，这道题的答案是 <strong>13 / 27</strong>，如果你算出来的不是这个数，那建议你继续往下看看。</p>
<h3>思维缜密的项目经理的解题思路</h3>
<p>项目经理小李，虽然数学功底不深，编程技术不精，但有个很大的好处是处事不惊，有条不紊。看到题目之后，略加思索，就用最简单的办法弄懂了这个问题，并求出了结果。</p>
<p>首先看如果只知道老王有两个孩子，其他信息都不知道的情况下，两个孩子都是男孩的概率显然是1/4。</p>
<p>再来看看没有“星期二”这个条件的情况，题目变成：老王有两个孩子，已知至少有一个孩子是男孩，问两个孩子都是男孩的概率是多大？那结果显然是1/3。因为在“至少有一个男孩”这样的条件下，只有三种可能：兄妹俩、姐弟俩、兄弟俩。这三种情况是等概率的，而只有一种情况是两个男孩，因此是1/3。</p>
<p>最后再把星期二也考虑进来。还是在上面的基础上扩展，先按照两个孩子的四种可能的性别组合进行划分，然后在每种组合里看看满足有至少一个周二男孩的情况数目：</p>
<ul>
<li>姐妹俩：不用看了，不满足至少有一个周二男孩的条件。</li>
<li>兄妹俩：那哥哥一定是周二出生的了，妹妹出生的星期数有7种可能。</li>
<li>姐弟俩：弟弟一定是周二出生，姐姐出生的星期数有7种可能。</li>
<li>兄弟俩：兄弟二人出生的星期数总共有7 * 7 = 49种可能，但其中有6 * 6 = 36种都不满足至少有一个人是周二出生的条件，因此实际上有49 - 36 = 13种可能。</li>
</ul>
<p>因此，满足条件的情况（这里的情况是指综合考虑孩子的性别和出生星期数）总数为7 + 7 + 13 = 27。而其中有13中可能对应于两个孩子都是男孩。因此题目所求概率是<strong>17 / 23</strong>。</p>
<p>没错，17 / 23就是这道题的答案，出现这样的数字是因为已知条件所提供的信息使得样本空间发生了变化（变小了一点儿）。这就是条件概率带来的影响。</p>
<h3>博学多才的数据挖掘专家的解题思路</h3>
<p>小陈是一个有丰富的数据挖掘和机器学习经验的专家，在听到这个题目的时候，想都没想，干脆地说：“这题简单，用贝叶斯公式就能搞定”。</p>
<p>根据题目，可以认定两个事件，事件A是：至少有一个周二出生的男孩；事件B是：两个孩子都是男孩。题目要求的是P(B|A)即在事件A发生的条件下，事件B发生的概率。根据贝叶斯公式，容易知道：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_6566d115b5451292e476fe543407fb46.gif' style='vertical-align: middle; border: none; ' class='tex' alt="P(B|A)=\frac{P(AB)}{P(A)}=\frac{P(A|B)P(B)}{P(A)}" title="P(B|A)=\frac{P(AB)}{P(A)}=\frac{P(A|B)P(B)}{P(A)}" /></span><script type='math/tex'>P(B|A)=\frac{P(AB)}{P(A)}=\frac{P(A|B)P(B)}{P(A)}</script></p>
<p>依次算出等号右边的各个概率值：</p>
<ul>
<li>在已知两个孩子都是男孩的条件下，至少有一个是周二出生的男孩：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_f536208fdee6a9d259249d559ae91dbf.gif' style='vertical-align: middle; border: none; ' class='tex' alt="P(A|B)=1-{(\frac{6}{7})}^2=\frac{13}{49}" title="P(A|B)=1-{(\frac{6}{7})}^2=\frac{13}{49}" /></span><script type='math/tex'>P(A|B)=1-{(\frac{6}{7})}^2=\frac{13}{49}</script></li>
<li>两个孩子都是男孩：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_df1d801ac8bc2515727e97e265940ebb.gif' style='vertical-align: middle; border: none; ' class='tex' alt="P(B)=\frac{1}{4}" title="P(B)=\frac{1}{4}" /></span><script type='math/tex'>P(B)=\frac{1}{4}</script></li>
<li>至少有一个孩子是周二出生的男孩：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_f5ed6ae1389fe491d1dba31f333b72d2.gif' style='vertical-align: middle; border: none; ' class='tex' alt="P(A)=1-{(\frac{1}{2}\times \frac{6}{7}+\frac{1}{2})}^2=\frac{27}{196}" title="P(A)=1-{(\frac{1}{2}\times \frac{6}{7}+\frac{1}{2})}^2=\frac{27}{196}" /></span><script type='math/tex'>P(A)=1-{(\frac{1}{2}\times \frac{6}{7}+\frac{1}{2})}^2=\frac{27}{196}</script></li>
</ul>
<p>因此可以求出：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_848b58a8c776138741f55e64aa3045cf.gif' style='vertical-align: middle; border: none; ' class='tex' alt="P(B|A)=\frac{P(A|B)P(B)}{P(A)}=\frac{13}{49}\times \frac{1}{4}\div \frac{27}{196}=\frac{13}{27}" title="P(B|A)=\frac{P(A|B)P(B)}{P(A)}=\frac{13}{49}\times \frac{1}{4}\div \frac{27}{196}=\frac{13}{27}" /></span><script type='math/tex'>P(B|A)=\frac{P(A|B)P(B)}{P(A)}=\frac{13}{49}\times \frac{1}{4}\div \frac{27}{196}=\frac{13}{27}</script></p>
<h3>苦逼的无证程序员的解题方法</h3>
<p>无证程序员小周看到题目后，二话不说，写了一小段程序（Python）来计算概率的近似值：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">random</span> <span style="color: #ff7700;font-weight:bold;">import</span> Random<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> IsTwoBoys<span style="color: black;">&#40;</span>rand<span style="color: black;">&#41;</span>:<br />
&nbsp; genders <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'M'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'F'</span><span style="color: black;">&#41;</span><br />
&nbsp; weekdays <span style="color: #66cc66;">=</span> <span style="color: #008000;">tuple</span><span style="color: black;">&#40;</span><span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">8</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:<br />
&nbsp; &nbsp; children <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>rand.<span style="color: black;">choice</span><span style="color: black;">&#40;</span>genders<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> rand.<span style="color: black;">choice</span><span style="color: black;">&#40;</span>weekdays<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>children<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'M'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> children<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">or</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: black;">&#40;</span>children<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'M'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> children<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span> <span style="color: #ff7700;font-weight:bold;">if</span> children<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">==</span> children<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'M'</span> <span style="color: #ff7700;font-weight:bold;">else</span> <span style="color: #008000;">False</span><br />
<br />
cnt <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1000000</span><br />
twoboys <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span><br />
rand <span style="color: #66cc66;">=</span> Random<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>cnt<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> IsTwoBoys<span style="color: black;">&#40;</span>rand<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; twoboys +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'p(twoboys) ='</span><span style="color: #66cc66;">,</span> twoboys<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'/'</span><span style="color: #66cc66;">,</span> cnt<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'='</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>twoboys<span style="color: black;">&#41;</span> / cnt</div></td></tr></tbody></table></div></pre>
<p>运行结果，题目所求概率值近似为：0.48213，与13 / 27 = 0.(481)非常接近。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/shuffle-algo.html' rel='bookmark' title='等概率随机排列数组（洗牌算法）'>等概率随机排列数组（洗牌算法）</a></li>
<li><a href='http://www.gocalf.com/blog/random-selection.html' rel='bookmark' title='单次遍历，等概率随机选取问题'>单次遍历，等概率随机选取问题</a></li>
<li><a href='http://www.gocalf.com/blog/unbalcanced-coin.html' rel='bookmark' title='利用不均匀硬币产生等概率'>利用不均匀硬币产生等概率</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection-2.html' rel='bookmark' title='单次遍历，带权随机选取问题（二）'>单次遍历，带权随机选取问题（二）</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/the-probability-of-two-boys.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>搞怪趣题：让11、12、13、14通过加减乘除运算得到46</title>
		<link>http://www.gocalf.com/blog/get-46-from-11-12-13-and-14.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=get-46-from-11-12-13-and-14</link>
		<comments>http://www.gocalf.com/blog/get-46-from-11-12-13-and-14.html#comments</comments>
		<pubDate>Thu, 15 Dec 2011 10:15:59 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[头脑风暴]]></category>
		<category><![CDATA[四则运算]]></category>
		<category><![CDATA[数学趣题]]></category>
		<category><![CDATA[智力题]]></category>
		<category><![CDATA[算24点]]></category>
		<category><![CDATA[脑筋急转弯]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1532</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/12/calc_46.png" class="attachment-post-thumbnail wp-post-image" alt="calc_46" title="calc_46" /></div>前两天同事的朋友给出了一个怪怪的题目，说是考验我们的智商，结果最后让我们大跌眼镜。

题目很简单：怎样让四个不同的数11、12、13和14，通过简单的数学运算得到46，可以使用加减乘除和括号。同时还给了一条重要提示：不能按照正常的思路思考。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/12/calc_46.png" class="attachment-post-thumbnail wp-post-image" alt="calc_46" title="calc_46" /></div><p>前两天同事的朋友给出了一个怪怪的题目，说是考验我们的智商，结果最后让我们大跌眼镜。</p>
<p>题目很简单：怎样让四个不同的数11、12、13和14，通过简单的数学运算得到46，可以使用加减乘除和括号。同时还给了一条重要提示：<strong>不能按照正常的思路思考</strong>。<span id="more-1532"></span></p>
<p>虽然说不能按照正常思路思考，但看到这个题目后还是立刻祭出了n年前写的算24点的程序，这个程序（以后有时间可以好好介绍一下）的扩展版支持由任意2到7个数字通过四则运算求出任意目标数。把四个数字和目标数输入进去，果然无解。不过很快发现，如果数字可以重复，能够得到下面两个最简单的解：</p>
<ul>
<li>使用两次11：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_6e02004d3c5754213b7e7959c313349c.gif' style='vertical-align: middle; border: none; ' class='tex' alt="11+13+11\times(14-12)=46" title="11+13+11\times(14-12)=46" /></span><script type='math/tex'>11+13+11\times(14-12)=46</script></li>
<li>使用两次12：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_4236c34debe733418c9336a756662880.gif' style='vertical-align: middle; border: none; ' class='tex' alt="(11+12)\times(12+14)/13=46" title="(11+12)\times(12+14)/13=46" /></span><script type='math/tex'>(11+12)\times(12+14)/13=46</script></li>
</ul>
<p>可惜出题人并不允许使用重复的数字，要求给定的每个数字必须用且仅用一次。</p>
<p>后来我就想会不会用到其他进制，搞IT的，总得玩玩什么二进制、八进制、十六进制之类的。但是应该采用哪个进制呢？想了好久，总算让我找到一个解：</p>
<ul>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_7b6605c1913d010fb4f80f5ca219878c.gif' style='vertical-align: middle; border: none; ' class='tex' alt="14+12\times(13-11)=46_{oct}" title="14+12\times(13-11)=46_{oct}" /></span><script type='math/tex'>14+12\times(13-11)=46_{oct}</script></li>
</ul>
<p>也就是把46按照八进制数来考虑。结果出题人告知：“<strong>是十进制的46</strong>”。看来进制转换的路走不通了，于是我又想出了其他一堆更不靠谱的解：</p>
<ul>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_93ccf008a0ae678d161c6b2d7dd2a3d5.gif' style='vertical-align: middle; border: none; ' class='tex' alt="(11+12)\ll(14-13)=46" title="(11+12)\ll(14-13)=46" /></span><script type='math/tex'>(11+12)\ll(14-13)=46</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_bee225f706fde039d011a04e62a39672.gif' style='vertical-align: middle; border: none; ' class='tex' alt="(11+12)\times\left\lceil\frac{14}{13}\right\rceil=46" title="(11+12)\times\left\lceil\frac{14}{13}\right\rceil=46" /></span><script type='math/tex'>(11+12)\times\left\lceil\frac{14}{13}\right\rceil=46</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_90e5f69659dd2d1645751086e23d72a3.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\sum_{i=13}^{14}{(11+12)}=46" title="\sum_{i=13}^{14}{(11+12)}=46" /></span><script type='math/tex'>\sum_{i=13}^{14}{(11+12)}=46</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_e1bab368eb0c4bea3e09cc9d8ab00b47.gif' style='vertical-align: middle; border: none; ' class='tex' alt="(11+12)\times\left|\left\{13,14\right\}\right|=46" title="(11+12)\times\left|\left\{13,14\right\}\right|=46" /></span><script type='math/tex'>(11+12)\times\left|\left\{13,14\right\}\right|=46</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_ca1b211346590096d2499e02b94bf833.gif' style='vertical-align: middle; border: none; ' class='tex' alt="(11+12)\times\left(e^{14i\pi}-e^{13i\pi}\right)=46" title="(11+12)\times\left(e^{14i\pi}-e^{13i\pi}\right)=46" /></span><script type='math/tex'>(11+12)\times\left(e^{14i\pi}-e^{13i\pi}\right)=46</script></li>
</ul>
<p>很明显越来越扯了，每个解法都引入了四则运算之外的运算符或者函数，都不是正确的解。</p>
<p>在苦思不得其解之后，出题人给出了他的答案，我们都震惊了。不过说实在的，我上面给的八进制的解跟答案非常接近了，只怪我没有深入理解出题人的告知。</p>
<p>正确答案是：</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<ul>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_21700e660ac46b74a61b7e962471cc32.gif' style='vertical-align: middle; border: none; ' class='tex' alt="11_{bin}+12_{oct}+13_{dec}+14_{hex}=46_{dec}" title="11_{bin}+12_{oct}+13_{dec}+14_{hex}=46_{dec}" /></span><script type='math/tex'>11_{bin}+12_{oct}+13_{dec}+14_{hex}=46_{dec}</script></li>
</ul>
<p>原来，出题人说“是十进制的46”，其内在含义是说：其他数字不一定是十进制。哈哈！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/get-46-from-11-12-13-and-14.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone开发：在UIAlertView中显示进度条</title>
		<link>http://www.gocalf.com/blog/iphone-dev-progressview-in-alertview.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=iphone-dev-progressview-in-alertview</link>
		<comments>http://www.gocalf.com/blog/iphone-dev-progressview-in-alertview.html#comments</comments>
		<pubDate>Fri, 09 Dec 2011 10:27:13 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[程序开发]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPhone 开发]]></category>
		<category><![CDATA[ObjC]]></category>
		<category><![CDATA[progress bar]]></category>
		<category><![CDATA[UIAlertView]]></category>
		<category><![CDATA[UIProgressView]]></category>
		<category><![CDATA[进度条]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1508</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/12/progress_icon.png" class="attachment-post-thumbnail wp-post-image" alt="progress_icon" title="progress_icon" /></div>今天这个问题是，在一个iPhone程序中，我要在后台做大量的数据处理，希望在界面上显示一个进度条（Progress Bar）使得用户了解处理进度。这个进度条应该是在一个模态的窗口中，使界面上其他控件无法被操作。怎么用最简单的方法来实现这个功能？UIAlertView是一个现成的模态窗口，如果能把进度条嵌入到它里面就好了。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/12/progress_icon.png" class="attachment-post-thumbnail wp-post-image" alt="progress_icon" title="progress_icon" /></div><p>今天这个问题是，在一个iPhone程序中，我要在后台做大量的数据处理，希望在界面上显示一个进度条（Progress Bar）使得用户了解处理进度。这个进度条应该是在一个模态的窗口中，使界面上其他控件无法被操作。怎么用最简单的方法来实现这个功能？<a href="http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIAlertView_Class/UIAlertView/UIAlertView.html" target="_blank">UIAlertView</a>是一个现成的模态窗口，如果能把进度条嵌入到它里面就好了。<span id="more-1508"></span></p>
<p>以下内容适用于iOS 2.0+。</p>
<p>我们知道，如果要显示一个alert窗口（比如用来显示错误或警告信息、询问用户是否确认某操作等等），只要简单地创建一个UIAlertView对象，再调用其show方法即可。示意代码如下：</p>
<pre><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">UIAlertView<span style="color: #002200;">*</span> alertView <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIAlertView alloc<span style="color: #002200;">&#93;</span> initWithTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Title&quot;</span><br />
&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;message<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Message&quot;</span><br />
&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; delegate<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cancelButtonTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;OK&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;otherButtonTitles<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; autorelease<span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#91;</span>alertView show<span style="color: #002200;">&#93;</span>;</div></td></tr></tbody></table></div></pre>
<p>如果要添加一个进度条，只要先创建并设置好一个<a href="http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIProgressView_Class/Reference/Reference.html" target="_blank">UIProgressView</a>的实例，再利用addSubbiew方法添加到alertView中即可。</p>
<p>在实际应用中，我可能需要在类中保存进度条的对象实例，以便更新其状态，因此先在自己的ViewController类中添加成员变量：</p>
<pre><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// &nbsp;MySampleViewController.h</span><br />
<span style="color: #6e371a;">#import &lt;UIKit/UIKit.h&gt;</span><br />
<br />
<span style="color: #a61390;">@interface</span> MySampleViewController <span style="color: #002200;">:</span> UIViewController <span style="color: #002200;">&#123;</span><br />
<span style="color: #a61390;">@private</span><br />
&nbsp; &nbsp; UIProgressView<span style="color: #002200;">*</span> progressView_;<br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #a61390;">@end</span></div></td></tr></tbody></table></div></pre>
<p>接下来写一个叫做showProgressAlert的方法来创建并显示带有进度条的alert窗口，其中高亮的部分就是把进度条添加到alertView中：</p>
<pre><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>showProgressAlert<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>title withMessage<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>message <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; UIAlertView<span style="color: #002200;">*</span> alertView <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIAlertView alloc<span style="color: #002200;">&#93;</span> initWithTitle<span style="color: #002200;">:</span>title<br />
&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;message<span style="color: #002200;">:</span>message<br />
&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; delegate<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cancelButtonTitle<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;otherButtonTitles<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; autorelease<span style="color: #002200;">&#93;</span>;<br />
<br />
<span style="display:block;background-color:#ffff66">&nbsp; &nbsp; progressView_ <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIProgressView alloc<span style="color: #002200;">&#93;</span> initWithProgressViewStyle<span style="color: #002200;">:</span>UIProgressViewStyleBar<span style="color: #002200;">&#93;</span>;<br /></span><span style="display:block;background-color:#ffff66">&nbsp; &nbsp; progressView_.frame <span style="color: #002200;">=</span> CGRectMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">30</span>, <span style="color: #2400d9;">80</span>, <span style="color: #2400d9;">225</span>, <span style="color: #2400d9;">30</span><span style="color: #002200;">&#41;</span>;<br /></span><span style="display:block;background-color:#ffff66">&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>alertView addSubview<span style="color: #002200;">:</span>progressView_<span style="color: #002200;">&#93;</span>;<br /></span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>alertView show<span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></pre>
<p>为了让数据处理的子进程能够方便地修改进度条的值，再添加一个简单的方法：</p>
<pre><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>updateProgress<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>progress <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; progressView_.progress <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>progress floatValue<span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></pre>
<p>另外，数据处理完毕后，我们还需要让进度条以及alertView消失，由于之前并没有保存alertView的实例，可以通过进度条的superview访问之：</p>
<pre><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dismissProgressAlert <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>progressView_ <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">return</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>progressView_.superview isKindOfClass<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>UIAlertView class<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; UIAlertView<span style="color: #002200;">*</span> alertView <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span>UIAlertView<span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>progressView_.superview;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>alertView dismissWithClickedButtonIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">0</span> animated<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>progressView_ release<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; progressView_ <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></pre>
<p>假设处理数据的方法叫processData，当然它会在一个单独的线程中运行，下面的片段示意了如何更新进度条状态，以及最后如何让它消失。</p>
<pre><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>processData<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">int</span><span style="color: #002200;">&#41;</span>total <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">for</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">int</span> i <span style="color: #002200;">=</span> <span style="color: #2400d9;">0</span>; i &lt; total; <span style="color: #002200;">++</span>i<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Update UI to show progess.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">float</span> progress <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>i <span style="color: #002200;">/</span> total;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a><span style="color: #002200;">*</span> progressNumber <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span style="color: #400080;">NSNumber</span></a> numberWithFloat<span style="color: #002200;">:</span>progress<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self performSelectorOnMainThread<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>updateProgress<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;withObject<span style="color: #002200;">:</span>progressNumber<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; waitUntilDone<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Process.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// do it.</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Finished.</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self performSelectorOnMainThread<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>dismissProgressAlert<span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;withObject<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; waitUntilDone<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Other finalizations.</span><br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></pre>
<p>在实际使用中，带进度条的alert view大概长得是这样的：</p>
<div id="attachment_1523" class="wp-caption alignnone" style="width: 604px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/12/progress_alert.png" alt="progress_alert" title="progress_alert" width="594" height="312" class="size-full wp-image-1523 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">带进度条的alert窗口</p></div>
<hr />
<p>参考：</p>
<ul>
<li><a href="https://discussions.apple.com/thread/1737797" target="_blank">UIProgressView in UIAlertView?</a></li>
</ul>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/iphone-dev-resizable-image.html' rel='bookmark' title='iPhone开发：可拉伸的图片'>iPhone开发：可拉伸的图片</a></li>
<li><a href='http://www.gocalf.com/blog/iphone-dev-range-slider.html' rel='bookmark' title='iPhone开发：自定义控件RangeSlider（范围滑动条）'>iPhone开发：自定义控件RangeSlider（范围滑动条）</a></li>
<li><a href='http://www.gocalf.com/blog/iphone-dev-hide-status-bar.html' rel='bookmark' title='iPhone开发：隐藏系统状态栏'>iPhone开发：隐藏系统状态栏</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/iphone-dev-progressview-in-alertview.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
	
		<series:name><![CDATA[iOS开发笔记]]></series:name>
	</item>
		<item>
		<title>iPhone开发：隐藏系统状态栏</title>
		<link>http://www.gocalf.com/blog/iphone-dev-hide-status-bar.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=iphone-dev-hide-status-bar</link>
		<comments>http://www.gocalf.com/blog/iphone-dev-hide-status-bar.html#comments</comments>
		<pubDate>Wed, 30 Nov 2011 06:45:48 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[程序开发]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPhone开发]]></category>
		<category><![CDATA[ObjC]]></category>
		<category><![CDATA[setStatusBarHidden]]></category>
		<category><![CDATA[Status Bar]]></category>
		<category><![CDATA[UIApplication]]></category>
		<category><![CDATA[隐藏状态栏]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1487</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/hide_status_bar.png" class="attachment-post-thumbnail wp-post-image" alt="hide_status_bar" title="hide_status_bar" /></div>最近在写iPhone上的程序，第一次在Mac下进行开发，也是第一次写手机上的程序，虽然之前看了少许相关的书籍，但在开发的过程中还是遇到了很多的问题。在这个系列中记录一些遇到的实际的问题，方便淡忘了之后再次查阅。

今天的问题是怎么在App中隐藏系统状态栏（Status Bar）。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/hide_status_bar.png" class="attachment-post-thumbnail wp-post-image" alt="hide_status_bar" title="hide_status_bar" /></div><p>最近在写iPhone上的程序，第一次在Mac下进行开发，也是第一次写手机上的程序，虽然之前看了少许相关的书籍，但在开发的过程中还是遇到了很多的问题。在这个系列中记录一些遇到的实际的问题，方便淡忘了之后再次查阅。</p>
<p>今天的问题是怎么在App中隐藏系统状态栏（Status Bar）。<span id="more-1487"></span></p>
<p>以下内容适用于iOS 3.2+。</p>
<h3>一、始终隐藏状态栏</h3>
<p>如果在App中需要状态栏一直是隐藏着的，可以在&lt;YOUR_APP&gt;AppDelegate的<code class="codecolorer objc geshi"><span class="objc">application<span style="color: #002200;">:</span>didFinishLaunchingWithOptions<span style="color: #002200;">:</span></span></code>函数中进行设置，比如下面这段示意代码可以让状态栏以淡出的方式隐藏起来：</p>
<pre><div class="codecolorer-container objc geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>application<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>UIApplication <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>application didFinishLaunchingWithOptions<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/"><span style="color: #400080;">NSDictionary</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>launchOptions <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Override point for customization after application launch.</span><br />
<span style="display:block;background-color:#ffff66">&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>application setStatusBarHidden<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span> withAnimation<span style="color: #002200;">:</span>UIStatusBarAnimationFade<span style="color: #002200;">&#93;</span>;<br /></span><br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// Add the view controller's view to the window and display.</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self.window addSubview<span style="color: #002200;">:</span>viewController.view<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self.window makeKeyAndVisible<span style="color: #002200;">&#93;</span>;<br />
<br />
&nbsp; &nbsp; <span style="color: #a61390;">return</span> <span style="color: #a61390;">YES</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div></pre>
<p>相关的方法或属性是<a href="http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html" target="_blank">UIApplication</a>的：</p>
<ul>
<li><a href="http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/occ/instm/UIApplication/setStatusBarHidden:withAnimation:" target="_blank">setStatusBarHidden:withAnimation:</a>（iOS 3.2+）</li>
<li><a href="http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/occ/instp/UIApplication/statusBarHidden" target="_blank">statusBarHidden</a>（iOS 2.0+）</li>
</ul>
<p>另外还有一个方法<a href="http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/DeprecationAppendix/AppendixADeprecatedAPI.html#//apple_ref/occ/instm/UIApplication/setStatusBarHidden:animated:" target="_blank">setStatusBarHidden:animated:</a>，已经不推荐使用了（deprecated in iOS 3.2）。</p>
<h3>二、App启动时就隐藏状态栏</h3>
<p>用了上面的方法之后，App在运行过程中，状态栏确实被隐藏起来了，但是我发现在App启动的那个瞬间，还是可以看到状态栏的，然后一闪即过。虽然时间很短暂，看着还是很不舒服。为了让状态栏从启动的时候就隐藏起来，可以修改&lt;YOUR_APP&gt;-Info.plist。如果在Xcode中修改，在根结点Infomation Property List下面新加一项“Status bar is initially hidden”（不用手动输入，可以直接在下拉菜单中选取）。这是个BOOL类型的键值，将Value栏中的复选框勾选上即可。</p>
<div id="attachment_1495" class="wp-caption alignnone" style="width: 332px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/status_bar_initially_hidden.png" alt="status_bar_initially_hidden" title="status_bar_initially_hidden" width="322" height="65" class="size-full wp-image-1495 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">在Info.plist中设置状态栏为隐藏</p></div>
<p>也可以以文本方式修改，在根节点中添加UIStatusBarHidden键值，值设为true即可：</p>
<pre><div class="codecolorer-container xml geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>UIStatusBarHidden<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;true</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span></div></td></tr></tbody></table></div></pre>
<h3>三、在运行过程中隐藏或显示状态栏</h3>
<p>与第一段中的方法一样，只是可以在任何地方调用。只要利用UIApplication类的静态方法<a href="http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/occ/clm/UIApplication/sharedApplication" target="_blank">sharedApplication</a>拿到application实例即可。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/iphone-dev-resizable-image.html' rel='bookmark' title='iPhone开发：可拉伸的图片'>iPhone开发：可拉伸的图片</a></li>
<li><a href='http://www.gocalf.com/blog/iphone-dev-range-slider.html' rel='bookmark' title='iPhone开发：自定义控件RangeSlider（范围滑动条）'>iPhone开发：自定义控件RangeSlider（范围滑动条）</a></li>
<li><a href='http://www.gocalf.com/blog/iphone-dev-progressview-in-alertview.html' rel='bookmark' title='iPhone开发：在UIAlertView中显示进度条'>iPhone开发：在UIAlertView中显示进度条</a></li>
<li><a href='http://www.gocalf.com/blog/hide-drive-q.html' rel='bookmark' title='隐藏磁盘分区Q'>隐藏磁盘分区Q</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/iphone-dev-hide-status-bar.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[iOS开发笔记]]></series:name>
	</item>
		<item>
		<title>七阶魔方花样：5x5数独</title>
		<link>http://www.gocalf.com/blog/5x5-sudoku-in-vcube7.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=5x5-sudoku-in-vcube7</link>
		<comments>http://www.gocalf.com/blog/5x5-sudoku-in-vcube7.html#comments</comments>
		<pubDate>Sat, 26 Nov 2011 07:48:56 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[头脑风暴]]></category>
		<category><![CDATA[七阶魔方]]></category>
		<category><![CDATA[数独]]></category>
		<category><![CDATA[高阶魔方]]></category>
		<category><![CDATA[魔方]]></category>
		<category><![CDATA[魔方花样]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1456</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/cube7_icon.png" class="attachment-post-thumbnail wp-post-image" alt="cube7_icon" title="cube7_icon" /></div>之前有一段时间特别喜欢玩魔方，从二阶到七阶，在桌子上摆了长长的一排。后来听说九阶和十一阶也有卖的了，心中甚是痒痒，可惜囊中羞涩啊。

特别喜欢高阶魔方的一个原因，就是它们每个面上的小方格数很多（就像人们都喜欢高分辨率的显示屏一样），可以玩的花样也就多了很多。今天分享一下我的一个七阶魔方花样作品：混乱中的秩序——五阶数独。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/cube7_icon.png" class="attachment-post-thumbnail wp-post-image" alt="cube7_icon" title="cube7_icon" /></div><p>之前有一段时间特别喜欢玩魔方，从二阶到七阶，在桌子上摆了长长的一排。后来听说九阶和十一阶也有卖的了，心中甚是痒痒，可惜囊中羞涩啊。</p>
<p>特别喜欢高阶魔方的一个原因，就是它们每个面上的小方格数很多（就像人们都喜欢高分辨率的显示屏一样），可以玩的花样也就多了很多。今天分享一下我的一个七阶魔方花样作品：混乱中的秩序——五阶数独。<span id="more-1456"></span></p>
<p>看一看照片，你能发现其中的规律么？</p>
<div id="attachment_1468" class="wp-caption alignnone" style="width: 525px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/cube7_corner.png" alt="cube7_corner" title="cube7_corner" width="515" height="260" class="size-full wp-image-1468 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">七阶魔方花样（你能看出其中的规律么？）</p></div>
<p>如果边角处看不清楚，那再来看看六个面的特写：</p>
<div id="attachment_1469" class="wp-caption alignnone" style="width: 525px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/cube7_face.png" alt="cube7_face" title="cube7_face" width="515" height="770" class="size-full wp-image-1469 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">七阶魔方花样，六个面特写——混乱中亦有规律</p></div>
<p>是不是有点儿意思？</p>
<p>规律是这样的，一个面周围一圈棱边的小方格颜色是一样的，六个面六种颜色。中间五乘五的二十五个小方格，恰好包含除了棱边之外的五种颜色，且每个颜色恰好出现五次。并且每个横行、竖列和两条对角线上的五个方格中都不出现重复颜色。这是不是跟五阶<a href="http://zh.wikipedia.org/wiki/%E5%AF%B9%E8%A7%92%E7%BA%BF%E6%95%B0%E7%8B%AC" target="_blank">对角线数独</a>非常像呢？</p>
<p>怎么设计这样的花样？关键在于，什么样的花样可以用魔方表现出来？</p>
<div id="attachment_1475" class="wp-caption alignnone" style="width: 243px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/cube7_blocks.png" alt="cube7_blocks" title="cube7_blocks" width="233" height="233" class="size-full wp-image-1475 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">七阶魔方面块的不同位置</p></div>
<p>上面这张图是七阶魔方的一个面的示意。由于我的这个花样方案中不用考虑棱块和角块，再除去不会动的面心，剩下的24个方格由于旋转对称性可以分成四个等价的分区（图中用四种颜色表示）。每个分区中都有六个不同的位置，用不同的字母表示。根据魔方的运动规律，不同字母位置的方块是永远都不会互换的，就是说字母A永远不会跑到其他字母所在的位置去；但是任意两个（也可以是不同面的）相同字母位置的方块都是可以互换的（只考虑颜色的话，可以做到互换后不改变任何其他方块）。每个面都有六种不同的字母，每个字母出现四次。因此只要设计出来的花样满足：“每个字母在六个面中总共对应4 * 6 = 24个方格，在这些方格中每种颜色都恰好出现4次”，那这种花样就一定可以转的出来。</p>
<p>接着来设计花样，先找一个五阶对角线数独的分布，用下面这段随意写出的Python代码就可以搞定。</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> FillBoard<span style="color: black;">&#40;</span>board<span style="color: #66cc66;">,</span> n<span style="color: #66cc66;">,</span> xy<span style="color: black;">&#41;</span>:<br />
&nbsp; x <span style="color: #66cc66;">=</span> xy % n<br />
&nbsp; y <span style="color: #66cc66;">=</span> xy // n<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> y <span style="color: #66cc66;">&gt;=</span> n:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Find a possible solution.'</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span><br />
<br />
&nbsp; existValues <span style="color: #66cc66;">=</span> <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; existValues <span style="color: #66cc66;">=</span> existValues.<span style="color: black;">union</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>board<span style="color: black;">&#91;</span>y<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>xx<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> xx <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; existValues <span style="color: #66cc66;">=</span> existValues.<span style="color: black;">union</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>board<span style="color: black;">&#91;</span>yy<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>x<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> yy <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> x <span style="color: #66cc66;">==</span> y:<br />
&nbsp; &nbsp; existValues <span style="color: #66cc66;">=</span> existValues.<span style="color: black;">union</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>board<span style="color: black;">&#91;</span>xx<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>xx<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> xx <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> x + y <span style="color: #66cc66;">==</span> n - <span style="color: #ff4500;">1</span>:<br />
&nbsp; &nbsp; existValues <span style="color: #66cc66;">=</span> existValues.<span style="color: black;">union</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>board<span style="color: black;">&#91;</span>xx<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>n-xx-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> xx <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
<br />
&nbsp; validValues <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>v <span style="color: #ff7700;font-weight:bold;">for</span> v <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> n+<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> v <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> existValues<span style="color: black;">&#93;</span><br />
<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> validValues: <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">False</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> v <span style="color: #ff7700;font-weight:bold;">in</span> validValues:<br />
&nbsp; &nbsp; board<span style="color: black;">&#91;</span>y<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>x<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> v<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> FillBoard<span style="color: black;">&#40;</span>board<span style="color: #66cc66;">,</span> n<span style="color: #66cc66;">,</span> xy+<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>: <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span><br />
&nbsp; &nbsp; board<span style="color: black;">&#91;</span>y<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>x<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">False</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> GenerateBoard<span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span>:<br />
&nbsp; board <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> y <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> FillBoard<span style="color: black;">&#40;</span>board<span style="color: #66cc66;">,</span> n<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'No solution.'</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> board<br />
<br />
cnt <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">5</span><br />
board <span style="color: #66cc66;">=</span> GenerateBoard<span style="color: black;">&#40;</span>cnt<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div></pre>
<p>用程序找到第一组解是：</p>
<pre><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[1, 2, 3, 4, 5]<br />
[2, 4, 5, 3, 1]<br />
[5, 3, 2, 1, 4]<br />
[3, 1, 4, 5, 2]<br />
[4, 5, 1, 2, 3]</div></td></tr></tbody></table></div></pre>
<p>下面来确定每个数字在每一面所对应的颜色。首先六个面的面心是不能动的，因此每个面的2号颜色就都确定了。接着要考虑每个面的底色（就是棱块和角块的颜色），这个颜色不能随便选，要考虑魔方六个面的位置关系。我所选定的方案是，面心色蓝、红、绿、橙、黄、黑分别的对应于棱角色黑、蓝、黄、绿、橙、红。最后给每个面分配第1、3、4、5号颜色，稍微注意一下限制条件就好了。最后得到六个面的配色方案（程序中的W对应于黑色）：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> ApplyColor<span style="color: black;">&#40;</span>board<span style="color: #66cc66;">,</span> colors<span style="color: black;">&#41;</span>:<br />
&nbsp; newboard <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span>colors<span style="color: black;">&#91;</span>v<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> v <span style="color: #ff7700;font-weight:bold;">in</span> row<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> row <span style="color: #ff7700;font-weight:bold;">in</span> board<span style="color: black;">&#93;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> newboard<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> DrawBoard<span style="color: black;">&#40;</span>board<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> row <span style="color: #ff7700;font-weight:bold;">in</span> board:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>row<span style="color: black;">&#41;</span><br />
<br />
allcolors <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><br />
&nbsp; <span style="color: black;">&#91;</span><span style="color: #483d8b;">'B Center'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'R'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'B'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'O'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'W'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Y'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; <span style="color: black;">&#91;</span><span style="color: #483d8b;">'R Center'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'G'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'R'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'B'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'W'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Y'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; <span style="color: black;">&#91;</span><span style="color: #483d8b;">'G Center'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'O'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'G'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'R'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'W'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Y'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; <span style="color: black;">&#91;</span><span style="color: #483d8b;">'O Center'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'G'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'O'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'B'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'W'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Y'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; <span style="color: black;">&#91;</span><span style="color: #483d8b;">'Y Center'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'R'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Y'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'O'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'B'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'G'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; <span style="color: black;">&#91;</span><span style="color: #483d8b;">'W Center'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'R'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'W'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'O'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'G'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'B'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; <span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">for</span> colors <span style="color: #ff7700;font-weight:bold;">in</span> allcolors:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Colors:'</span><span style="color: #66cc66;">,</span> colors<span style="color: black;">&#41;</span><br />
&nbsp; colorboard <span style="color: #66cc66;">=</span> ApplyColor<span style="color: black;">&#40;</span>board<span style="color: #66cc66;">,</span> colors<span style="color: black;">&#41;</span><br />
&nbsp; DrawBoard<span style="color: black;">&#40;</span>colorboard<span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div></pre>
<p>最后一步就是纯体力活——转魔方。这里就不详细说了，基本的过程是先把棱块和角块转好，最后就可以随意调换每个面中部的颜色了。因为图案看起来乱乱的，转的时候很容易忘记哪边已经转好哪边还没转，只能是小心仔细慢慢进行。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/check-udisk.html' rel='bookmark' title='U盘检测软件：ChipGenius，MyDiskTest'>U盘检测软件：ChipGenius，MyDiskTest</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-characters.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：角色介绍'>《塞尔达传说：黎明公主》攻略：角色介绍</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-2.html' rel='bookmark' title='2011.5.15我们的婚礼（二）——迎亲篇'>2011.5.15我们的婚礼（二）——迎亲篇</a></li>
<li><a href='http://www.gocalf.com/blog/circle-of-link-list.html' rel='bookmark' title='检测单向链表是否存在环'>检测单向链表是否存在环</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/5x5-sudoku-in-vcube7.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>计算斐波纳契数，分析算法复杂度</title>
		<link>http://www.gocalf.com/blog/calc-fibonacci.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=calc-fibonacci</link>
		<comments>http://www.gocalf.com/blog/calc-fibonacci.html#comments</comments>
		<pubDate>Tue, 22 Nov 2011 12:34:30 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Fibonacci]]></category>
		<category><![CDATA[Master定理]]></category>
		<category><![CDATA[大整数运算]]></category>
		<category><![CDATA[斐波纳契数列]]></category>
		<category><![CDATA[矩阵乘方]]></category>
		<category><![CDATA[算法复杂度]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1406</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/fibonacci.png" class="attachment-post-thumbnail wp-post-image" alt="fibonacci" title="fibonacci" /></div>问题描述：Fibonacci数（Fibonacci Number）的定义是：F(n) = F(n - 1) + F(n - 2)，并且F(0) = 0，F(1) = 1。对于任意指定的整数n（n≥0），计算F(n)，并分析算法的时间、空间复杂度。

假设系统中已经提供任意精度长整数的运算，可以直接使用。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/fibonacci.png" class="attachment-post-thumbnail wp-post-image" alt="fibonacci" title="fibonacci" /></div><p>问题描述：Fibonacci数（<a href="http://en.wikipedia.org/wiki/Fibonacci_number" target="_blank">Fibonacci Number</a>）的定义是：F(n) = F(n - 1) + F(n - 2)，并且F(0) = 0，F(1) = 1。对于任意指定的整数n（n ≥ 0），计算F(n)的精确值，并分析算法的时间、空间复杂度。</p>
<p>假设系统中已经提供任意精度长整数的运算，可以直接使用。<span id="more-1406"></span></p>
<p>这其实是个老生常谈的问题了，不过可能在复杂度分析的时候，很多人忽略了一些事情。另外这个问题恰好有几种复杂度迥异的算法，在刚刚介绍完<a href="http://www.gocalf.com/blog/algorithm-complexity-and-master-theorem.html">算法复杂度</a>之后，正好来直观地理解一下。</p>
<h3>一、递归法</h3>
<p>一个看起来很直观、用起来很恐怖的算法就是递归法。根据Fibonacci的递推公式，对于输入的n，直接递归地调用相同的函数分别求出F(n - 1)和F(n - 2)，二者相加就是结果。递归的终止点就是递推方程的初值，即n取0或1的时候。</p>
<p>程序（in Python）写出来那也是相当的简洁直观（为了跟后面的程序区分开来，这里取名SlowFibonacci）。</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> SlowFibonacci<span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> n <span style="color: #66cc66;">&gt;=</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'invalid n'</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> n <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">2</span>: <span style="color: #ff7700;font-weight:bold;">return</span> n &nbsp;<span style="color: #808080; font-style: italic;"># F(0) = 0, F(1) = 1</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> SlowFibonacci<span style="color: black;">&#40;</span>n - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span> + SlowFibonacci<span style="color: black;">&#40;</span>n - <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div></pre>
<p>这个算法的时间复杂度有着跟Fibonacci类似的递推方程：T(n) = T(n - 1) + T(n - 2) + O(1)，很容易得到<strong>T(n) = O(1.618 ^ n)</strong>（1.618就是黄金分割，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_a7061313c467759c5124cde590116e18.gif' style='vertical-align: middle; border: none; ' class='tex' alt="(1+\sqrt5)/2 " title="(1+\sqrt5)/2 " /></span><script type='math/tex'>(1+\sqrt5)/2 </script>）。空间复杂度取决于递归的深度，显然是<strong>O(n)</strong>。</p>
<h3>二、递推法</h3>
<p>虽然只是一字之差，但递推法的复杂度要小的多。这个方法就是按照递推方程，从n = 0和n = 1开始，逐个求出所有小于n的Fibonacci数，最后就可以算出F(n)。由于每次计算值需要用到前两个Fibonacci数，更小的数就可以丢弃了，可以将空间复杂度降到最低。算法如下：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> NormFibonacci<span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> n <span style="color: #66cc66;">&gt;=</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'invalid n'</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> n <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span>: <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">0</span><br />
&nbsp; <span style="color: black;">&#40;</span>prev<span style="color: #66cc66;">,</span> curr<span style="color: black;">&#41;</span> <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span> &nbsp;<span style="color: #808080; font-style: italic;"># F(0), F(1)</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>prev<span style="color: #66cc66;">,</span> curr<span style="color: black;">&#41;</span> <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span>curr<span style="color: #66cc66;">,</span> prev + curr<span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> curr</div></td></tr></tbody></table></div></pre>
<p>显然时间复杂度是<strong>O(n)</strong>，空间复杂度是<strong>O(1)</strong>。</p>
<p>比较一下递归法和递推法，二者都用了分治的思想——把目标问题拆为若干个小问题，利用小问题的解得到目标问题的解。二者的区别实际上就是普通分治算法和动态规划的区别。</p>
<h3>三、矩阵法</h3>
<p>算Fibonacci数精确值的最快的方法应该就是矩阵法，看过的人都觉得这个方法很好。如果你跟我一样，曾经为记住这个方法中的矩阵而烦恼，那今天就来看看怎么进行推导。其实方法非常简单，想清楚了也就自然而然地记住了。</p>
<p>我们把Fibonacci数列中相邻的两项：F(n)和F(n - 1)写成一个2x1的矩阵，然后对其进行变形，看能得到什么：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_095f3f2456d98be838b0872393f879c0.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{bmatrix}F_n\\F_{n-1}\end{bmatrix}=\begin{bmatrix}F_{n-1}+F_{n-2}\\F_{n-1}\end{bmatrix}=\begin{bmatrix}1\times F_{n-1}+1\times F_{n-2}\\1\times F_{n-1}+0\times F_{n-2}\end{bmatrix}=\begin{bmatrix}1&1\\1&0\end{bmatrix}\times\begin{bmatrix}F_{n-1}\\F_{n-2}\end{bmatrix}" title="\begin{bmatrix}F_n\\F_{n-1}\end{bmatrix}=\begin{bmatrix}F_{n-1}+F_{n-2}\\F_{n-1}\end{bmatrix}=\begin{bmatrix}1\times F_{n-1}+1\times F_{n-2}\\1\times F_{n-1}+0\times F_{n-2}\end{bmatrix}=\begin{bmatrix}1&1\\1&0\end{bmatrix}\times\begin{bmatrix}F_{n-1}\\F_{n-2}\end{bmatrix}" /></span><script type='math/tex'>\begin{bmatrix}F_n\\F_{n-1}\end{bmatrix}=\begin{bmatrix}F_{n-1}+F_{n-2}\\F_{n-1}\end{bmatrix}=\begin{bmatrix}1\times F_{n-1}+1\times F_{n-2}\\1\times F_{n-1}+0\times F_{n-2}\end{bmatrix}=\begin{bmatrix}1&1\\1&0\end{bmatrix}\times\begin{bmatrix}F_{n-1}\\F_{n-2}\end{bmatrix}</script></p>
<p>是不是非常自然呢？把等式最右边继续算下去，最后得到：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_baffa39081d93459890754d9013f34fb.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{bmatrix}F_n\\F_{n-1}\end{bmatrix}=\begin{bmatrix}1&1\\1&0\end{bmatrix}^{n-1}\times\begin{bmatrix}F_{1}\\F_{0}\end{bmatrix}=\begin{bmatrix}1&1\\1&0\end{bmatrix}^{n-1}\times\begin{bmatrix}1\\0\end{bmatrix}" title="\begin{bmatrix}F_n\\F_{n-1}\end{bmatrix}=\begin{bmatrix}1&1\\1&0\end{bmatrix}^{n-1}\times\begin{bmatrix}F_{1}\\F_{0}\end{bmatrix}=\begin{bmatrix}1&1\\1&0\end{bmatrix}^{n-1}\times\begin{bmatrix}1\\0\end{bmatrix}" /></span><script type='math/tex'>\begin{bmatrix}F_n\\F_{n-1}\end{bmatrix}=\begin{bmatrix}1&1\\1&0\end{bmatrix}^{n-1}\times\begin{bmatrix}F_{1}\\F_{0}\end{bmatrix}=\begin{bmatrix}1&1\\1&0\end{bmatrix}^{n-1}\times\begin{bmatrix}1\\0\end{bmatrix}</script></p>
<p>因此要求F(n)，只要对这个二阶方阵求n - 1次方，最后取结果方阵第一行第一列的数字就可以了。</p>
<p>看起来有点儿化简为繁的感觉，但关键点在于，幂运算是可以二分加速的。设有一个方阵a，利用分治法求a的n次方，有：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_fb1e8809f959ea60ef0d1792a2052ef5.gif' style='vertical-align: middle; border: none; ' class='tex' alt="a^n=\begin{cases}a^{n/2}\times a^{n/2}&,\text{ if }x\text{ is even}\\a^{(n-1)/2}\times a^{(n-1)/2}\times a&,\text{ if }x\text{ is odd}\end{cases}" title="a^n=\begin{cases}a^{n/2}\times a^{n/2}&,\text{ if }x\text{ is even}\\a^{(n-1)/2}\times a^{(n-1)/2}\times a&,\text{ if }x\text{ is odd}\end{cases}" /></span><script type='math/tex'>a^n=\begin{cases}a^{n/2}\times a^{n/2}&,\text{ if }x\text{ is even}\\a^{(n-1)/2}\times a^{(n-1)/2}\times a&,\text{ if }x\text{ is odd}\end{cases}</script></p>
<p>可见复杂度满足T(n) = T(n / 2) + O(1)，根据<a href="http://www.gocalf.com/blog/algorithm-complexity-and-master-theorem.html">Master定理</a>可得：T(n) = O(log n)。</p>
<p>在实现的时候，可以用循环代替递归实现这里的二分分治，好处是降低了空间复杂度（用递归的话，空间复杂度为O(log n)）。下面的Python程序直接利用的numpy库中的矩阵乘法（当然这个库也实现了矩阵的幂运算，我把它单独写出来是为了强调这里的分治算法）。另外如果不用第三方库，我也给出了矩阵乘法的简单实现。</p>
<div id="wp-tabs-6" class="wp-tabs wpui-light wpui-styles"><h3 class="wp-tab-title">Using numpy Library</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> numpy <span style="color: #ff7700;font-weight:bold;">import</span> matrix<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> MatrixPower<span style="color: black;">&#40;</span>mat<span style="color: #66cc66;">,</span> n<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> n <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'invalid n'</span><br />
&nbsp; res <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><br />
&nbsp; temp <span style="color: #66cc66;">=</span> mat<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> n &amp; <span style="color: #ff4500;">1</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> res <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>: res <span style="color: #66cc66;">=</span> temp<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>: res <span style="color: #66cc66;">=</span> res * temp<br />
&nbsp; &nbsp; n <span style="color: #66cc66;">&gt;&gt;=</span> <span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> n <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span>: <span style="color: #ff7700;font-weight:bold;">break</span><br />
&nbsp; &nbsp; temp <span style="color: #66cc66;">=</span> temp * temp<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> res<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> FastFibonacci<span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> n <span style="color: #66cc66;">&gt;=</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'invalid n'</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> n <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">2</span>: <span style="color: #ff7700;font-weight:bold;">return</span> n &nbsp;<span style="color: #808080; font-style: italic;"># F(0) = 0, F(1) = 1</span><br />
&nbsp; mat <span style="color: #66cc66;">=</span> matrix<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> dtype<span style="color: #66cc66;">=</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span><br />
&nbsp; mat <span style="color: #66cc66;">=</span> MatrixPower<span style="color: black;">&#40;</span>mat<span style="color: #66cc66;">,</span> n - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> mat<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<h3 class="wp-tab-title">Without numpy Library</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> DotProduct<span style="color: black;">&#40;</span>x<span style="color: #66cc66;">,</span> y<span style="color: black;">&#41;</span>:<br />
&nbsp; n <span style="color: #66cc66;">=</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>y<span style="color: black;">&#41;</span> <span style="color: #66cc66;">==</span> n<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'x and y must have the same length'</span><br />
&nbsp; s <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; s +<span style="color: #66cc66;">=</span> x<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span> * y<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> s<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> MatrixMultiply<span style="color: black;">&#40;</span>x<span style="color: #66cc66;">,</span> y<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #808080; font-style: italic;"># x is a m*a matrix, y is a a*n matrix.</span><br />
&nbsp; <span style="color: #808080; font-style: italic;"># x * y is a m*n matrix.</span><br />
&nbsp; m <span style="color: #66cc66;">=</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><br />
&nbsp; n <span style="color: #66cc66;">=</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>y<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; a <span style="color: #66cc66;">=</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>y<span style="color: black;">&#41;</span> <span style="color: #66cc66;">==</span> a<br />
<br />
&nbsp; <span style="color: #808080; font-style: italic;"># transpose y</span><br />
&nbsp; y <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span>y<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>a<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
<br />
&nbsp; res <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span>DotProduct<span style="color: black;">&#40;</span>x<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> y<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>m<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> res<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> MatrixPower<span style="color: black;">&#40;</span>mat<span style="color: #66cc66;">,</span> n<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> n <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'invalid n'</span><br />
&nbsp; res <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><br />
&nbsp; temp <span style="color: #66cc66;">=</span> mat<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> n &amp; <span style="color: #ff4500;">1</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> res <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>: res <span style="color: #66cc66;">=</span> temp<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>: res <span style="color: #66cc66;">=</span> MatrixMultiply<span style="color: black;">&#40;</span>res<span style="color: #66cc66;">,</span> temp<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; n <span style="color: #66cc66;">&gt;&gt;=</span> <span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> n <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span>: <span style="color: #ff7700;font-weight:bold;">break</span><br />
&nbsp; &nbsp; temp <span style="color: #66cc66;">=</span> MatrixMultiply<span style="color: black;">&#40;</span>temp<span style="color: #66cc66;">,</span> temp<span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> res<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> FastFibonacci<span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> n <span style="color: #66cc66;">&gt;=</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'invalid n'</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> n <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">2</span>: <span style="color: #ff7700;font-weight:bold;">return</span> n &nbsp;<span style="color: #808080; font-style: italic;"># F(0) = 0, F(1) = 1</span><br />
&nbsp; mat <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span><br />
&nbsp; mat <span style="color: #66cc66;">=</span> MatrixPower<span style="color: black;">&#40;</span>mat<span style="color: #66cc66;">,</span> n - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> mat<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></div><!-- end div.wp-tabs --></pre>
<p>二阶方阵相乘一次可以看成是常数时间（虽然这个常数会比较大），因此整个算法的时间复杂度是<strong>O(log n)</strong>，空间复杂度是<strong>O(1)</strong>。</p>
<h3>四、运行时间大比拼</h3>
<p>至此，我们得到的时间复杂度分别是O(1.618 ^ n)、O(n)和O(log n)的算法，让我们来直观地比较比较它们。</p>
<p>用Python的timeit模块对以上三个算法的运行时间进行了测量，记录了每个算法对于不同的n的每千次运算所消耗的时间（单位是秒），部分数据记录在<a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/fibonacci_data.zip">fibonacci_data</a>。利用Mathematica可以很方便地对这些数据进行拟合，对于较小的n，用三个复杂度表达式分别去拟合，得到的效果都非常好。尤其值得注意的是，对于第一个算法，我用a * b ^ n去拟合，结果得到b等于1.61816，这与黄金分割数的正确值相差无几。</p>
<ul>
<li>递归法拟合结果：0.000501741 *&nbsp;1.61816 ^ n，RSquare =&nbsp;0.999993。</li>
<li>递推法拟合结果：0.000788421&nbsp;+ 0.000115831 * n，RSquare =&nbsp;0.999464。</li>
<li>矩阵法拟合结果：-0.0114923 + 0.0253609 log(n)，RSquare =&nbsp;0.986576。</li>
</ul>
<p>下图是n ≤ 35时，三种算法的千次运行耗时比较。其中红色为O(1.618 ^ n)的递归法；蓝色为O(n)的递推法；绿色为O(log n)的矩阵法。散点为实际测量到的运行时间，实线为拟合方程的曲线。</p>
<div id="attachment_1427" class="wp-caption alignnone" style="width: 547px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/compare_a.png" alt="compare_a" title="compare_a" width="537" height="344" class="size-full wp-image-1427 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">三种算法的运行时间比较</p></div>
<p>当n > 10的时候，指数时间就已经超出画面范围了。另外在这张图里，身为对数时间复杂度的矩阵法似乎没有任何优势，其耗时远远高于线性时间复杂度的递推法。这是因为n还不够大，体现不出log(n)的优势。在考虑更大的n之前，先来看看指数时间复杂度会增大到什么程度。</p>
<div id="attachment_1430" class="wp-caption alignnone" style="width: 547px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/compare_b.png" alt="compare_b" title="compare_b" width="537" height="338" class="size-full wp-image-1430 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">三种算法的运行时间比较（对数坐标轴）</p></div>
<h3>五、大整数情况下的复杂度</h3>
<p>Python内置了大整数支持，因此上面的程序都可以直接接受任意大的n。当整数在32位或64位以内时，加法和乘法都是常数时间，但大整数情况下，这个时间就不能忽略了。</p>
<p>先来看一下Fibonacci数的二进制位数。我们知道Fibonacci数的通项公式是：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_5a724afb37283fa1e4e8733454236cf4.gif' style='vertical-align: middle; border: none; ' class='tex' alt="F_n=\frac{1}{\sqrt5}\left(\frac{1+\sqrt5}{2}\right)^n-\frac{1}{\sqrt5}\left(\frac{1-\sqrt5}{2}\right)^n" title="F_n=\frac{1}{\sqrt5}\left(\frac{1+\sqrt5}{2}\right)^n-\frac{1}{\sqrt5}\left(\frac{1-\sqrt5}{2}\right)^n" /></span><script type='math/tex'>F_n=\frac{1}{\sqrt5}\left(\frac{1+\sqrt5}{2}\right)^n-\frac{1}{\sqrt5}\left(\frac{1-\sqrt5}{2}\right)^n</script></p>
<p>当n充分大（其实都不需要很大）的时候，第二项就可以忽略不计了。把第一项对2取对数，就可以得到Fibonacci数的二进制位数的近似表达式，大概是<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_17dafae8933bfb1e14f8db7ecefd1fe5.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\log_2{1.618}\times n-0.5\log_2{5}/2=\log_2{1.618}\times n-1.161=O(n)" title="\log_2{1.618}\times n-0.5\log_2{5}/2=\log_2{1.618}\times n-1.161=O(n)" /></span><script type='math/tex'>\log_2{1.618}\times n-0.5\log_2{5}/2=\log_2{1.618}\times n-1.161=O(n)</script>。由此可以算出，F(47)是32位有符号整数可以表达的最大的Fibonacci数，F(93)是64位有符号整数可以表达的最大的Fibonacci数。上面图中的n在36以内，不需要动用大整数运算，复杂度也比较符合之前的结论。但对于更大的n，之前的复杂度就不再适用了。</p>
<p>指数复杂度的算法就不管了，还不等用到大整数，它就已经慢到不行了。</p>
<p>来看看O(n)时间复杂度的递推法。每次递推的时候都要计算两个Fibonacci数之和，第i次运算时，这两个Fibonacci数分别有O(i)个二进制位，完成加法需要O(i)的时间。因此总的时间大约是：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_9f411c08810e38cbfb80663b34d904d1.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\sum_{i=1}^n{O(i)}=O(n^2)" title="\sum_{i=1}^n{O(i)}=O(n^2)" /></span><script type='math/tex'>\sum_{i=1}^n{O(i)}=O(n^2)</script></p>
<p>可见对于很大的n，递推法的时间复杂度实际上是<strong>O(n ^ 2)</strong>的，空间复杂度是<strong>O(n)</strong>用来存储Fibonacci数的各个二进制位。</p>
<p>再看矩阵法，注意到矩阵运算中有乘法，两个长度为n的大整数相乘，传统算法是O(n ^ 2)时间复杂度，较好的Karatsuba算法是O(n ^ (log 3 / log 2))时间，更快的快速傅立叶变换法是O(n log n)时间。Python 2.5中使用的是Karatsuba算法（Python 3里面似乎是快速傅立叶变换法）（参见<a href="http://www.endless-loops.com/2011/01/python%E6%BA%90%E7%A0%81%E4%B8%AD%E7%9A%84%E7%AE%97%E6%B3%95%E5%88%86%E6%9E%90-%E4%B9%8B-%E5%A4%A7%E6%95%B4%E6%95%B0%E4%B9%98%E6%B3%95-378.html" target="_blank">Python源码中的算法分析 之 大整数乘法</a>）。以Karatsuba算法为例，矩阵法的时间复杂度递推方程为：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_63c22ce25deef6688d581e23cc96431f.gif' style='vertical-align: middle; border: none; ' class='tex' alt="T(n)=T(n/2)+O(n^{\log_2{3}})" title="T(n)=T(n/2)+O(n^{\log_2{3}})" /></span><script type='math/tex'>T(n)=T(n/2)+O(n^{\log_2{3}})</script>，应用<a href="http://www.gocalf.com/blog/algorithm-complexity-and-master-theorem.html">Master定理</a>求得<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_cba382411f26350ac7a25240bd2ea669.gif' style='vertical-align: middle; border: none; ' class='tex' alt="T(n)=O(n^{\log_2{3}})" title="T(n)=O(n^{\log_2{3}})" /></span><script type='math/tex'>T(n)=O(n^{\log_2{3}})</script>。因此对于很大的n，矩阵法的时间复杂度为<strong>O(n ^ 1.585)</strong>，空间复杂度<strong>O(n)</strong>。</p>
<p>利用Mathematica对大n情况下这两种算法每千次运行时间进行拟合，分别得到：</p>
<ul>
<li>递推法大整数拟合结果：0.0131216 + 0.000102101 * n + 2.44765 * 10 ^ -7 * n ^ 2，RSquare = 0.999482。</li>
<li>矩阵法大整数拟合结果：0.171487 + 9.74496 * 10 ^ -7 * n ^ 1.51827，RSquare =&nbsp;0.998395。</li>
</ul>
<p>看一下n在4000以内时，两种复杂度的对比情况：</p>
<div id="attachment_1437" class="wp-caption alignnone" style="width: 547px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/compare_c.png" alt="compare_c" title="compare_c" width="537" height="344" class="size-full wp-image-1437 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">递推法（蓝色）与矩阵法（绿色）运行时间比较（大整数）</p></div>
<p>从图中可以看出，递推法的增长速度也是很快的，当n增大到60多的时候，它的运行时间就超过矩阵法了。矩阵法的增长速度非常慢，看起来像是线性的，让我们把n调的更大来看一下。</p>
<div id="attachment_1438" class="wp-caption alignnone" style="width: 547px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/compare_d.png" alt="compare_d" title="compare_d" width="537" height="341" class="size-full wp-image-1438 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">矩阵法的运行时间（更大的n）</p></div>
<h3>六、更快的算法？</h3>
<p>试了试Mathematica中的Fibonacci函数，发现其运算速度相当惊人，估计时间复杂度在O(n log n)上下，而且对于相同的n，运算速度远远高于我的矩阵法。可惜我还不了解它的算法，只是在帮助文档里看到：</p>
<blockquote>
<p>Fibonacci[n] uses an iterative method based on the binary digit sequence of n.</p>
</blockquote>
<p>来看看它到底有多快：</p>
<div id="attachment_1446" class="wp-caption alignnone" style="width: 547px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/compare_e.png" alt="compare_e" title="compare_e" width="537" height="344" class="size-full wp-image-1446 wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">矩阵法（绿色）与Mathematica Fibonacci函数（橙色）运行时间比较</p></div>
<p>好吧，这个问题留待以后慢慢研究。</p>
<p>最后相关的Mathematica命令文件放在这里：<a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/fibonacci_timecost.zip">fibonacci_timecost</a></p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
<li><a href='http://www.gocalf.com/blog/unbalcanced-coin.html' rel='bookmark' title='利用不均匀硬币产生等概率'>利用不均匀硬币产生等概率</a></li>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection-2.html' rel='bookmark' title='单次遍历，带权随机选取问题（二）'>单次遍历，带权随机选取问题（二）</a></li>
<li><a href='http://www.gocalf.com/blog/random-selection.html' rel='bookmark' title='单次遍历，等概率随机选取问题'>单次遍历，等概率随机选取问题</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/calc-fibonacci.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>算法的复杂度与Master定理</title>
		<link>http://www.gocalf.com/blog/algorithm-complexity-and-master-theorem.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=algorithm-complexity-and-master-theorem</link>
		<comments>http://www.gocalf.com/blog/algorithm-complexity-and-master-theorem.html#comments</comments>
		<pubDate>Wed, 16 Nov 2011 06:16:35 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Master定理]]></category>
		<category><![CDATA[上界]]></category>
		<category><![CDATA[下界]]></category>
		<category><![CDATA[函数渐进阶]]></category>
		<category><![CDATA[时间复杂度]]></category>
		<category><![CDATA[算法复杂度]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1374</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/master_theorem.png" class="attachment-post-thumbnail wp-post-image" alt="master_theorem" title="master_theorem" /></div>平时设计或者阅读一个算法的时候，必然会提到算法的复杂度（包括时间复杂度和空间复杂度）。比如我们说一个二分查找算法的平均时间复杂度为O(log n)，快速排序可能是O(n log n)。那这里的O是什么意思？这样的表达是否准确呢？

今天来复习一下与算法复杂度相关的知识：函数渐进阶；记号O、Ω、θ和o；Master定理。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/master_theorem.png" class="attachment-post-thumbnail wp-post-image" alt="master_theorem" title="master_theorem" /></div><p>平时设计或者阅读一个算法的时候，必然会提到算法的复杂度（包括时间复杂度和空间复杂度）。比如我们说一个二分查找算法的平均时间复杂度为O(log n)，快速排序可能是O(n log n)。那这里的O是什么意思？这样的表达是否准确呢？</p>
<p>今天来复习一下与算法复杂度相关的知识：函数渐进阶，记号O、Ω、θ和o；Master定理。<span id="more-1374"></span></p>
<p>先插一句，在算法复杂度分析中，log通常表示以2为底的对数。</p>
<p>算法复杂度（算法复杂性）是用来衡量算法运行所需要的计算机资源（时间、空间）的量。通常我们利用渐进性态来描述算法的复杂度。</p>
<p>用n表示问题的规模，T(n)表示某个给定算法的复杂度。所谓渐进性态就是令n→∞时，T(n)中增长最快的那部分。严格的定义是：如果存在<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_80fd881af60235c5f6b291489711ded0.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\widetilde{T}(n)" title="\widetilde{T}(n)" /></span><script type='math/tex'>\widetilde{T}(n)</script>，当n→∞时，有</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_3edfc2e16566e2edb1052a4035bc3f82.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\frac{T(n)-\widetilde{T}(n)}{T(n)} \to 0" title="\frac{T(n)-\widetilde{T}(n)}{T(n)} \to 0" /></span><script type='math/tex'>\frac{T(n)-\widetilde{T}(n)}{T(n)} \to 0</script></p>
<p>就说<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_80fd881af60235c5f6b291489711ded0.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\widetilde{T}(n)" title="\widetilde{T}(n)" /></span><script type='math/tex'>\widetilde{T}(n)</script>是T(n)当n→∞时的渐进性态。</p>
<p>比如T(n) = 2 * n ^ 2 + n log n + 3，那么显然它的渐进性态是 2 * n ^ 2，因为当n→∞时，后两项的增长速度要慢的多，可以忽略掉。引入渐进性态是为了简化算法复杂度的表达式，只考虑其中的主要因素。当比较两个算法复杂度的时候，如果他们的渐进复杂度的阶不相同，那只需要比较彼此的阶（忽略常数系数）就可以了。</p>
<p>总之，分析算法复杂度的时候，并不用严格演算出一个具体的公式，而是只需要分析当问题规模充分大的时候，复杂度在渐进意义下的阶。记号O、Ω、θ和o可以帮助我们了解函数渐进阶的大小。</p>
<p>假设有两个函数f(n)和g(n)，都是定义在正整数集上的正函数。上述四个记号的含义分别是：</p>
<ul>
<li>f(n) = O(g(n))：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_806e626f15c347ab758e490b8e67c2f6.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\exists c>0,n_0\in\mathbb{N},\forall n\geq n_0,f(n)\leq c g(n)" title="\exists c>0,n_0\in\mathbb{N},\forall n\geq n_0,f(n)\leq c g(n)" /></span><script type='math/tex'>\exists c>0,n_0\in\mathbb{N},\forall n\geq n_0,f(n)\leq c g(n)</script>；f的阶<strong>不高于</strong>g的阶。</li>
<li>f(n) =&nbsp;Ω(g(n))：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_ab6ca1ba368e754432ff3d517811ce21.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\exists c>0,n_0\in\mathbb{N},\forall n\geq n_0,f(n)\geq c g(n)" title="\exists c>0,n_0\in\mathbb{N},\forall n\geq n_0,f(n)\geq c g(n)" /></span><script type='math/tex'>\exists c>0,n_0\in\mathbb{N},\forall n\geq n_0,f(n)\geq c g(n)</script>；f的阶<strong>不低于</strong>g的阶。</li>
<li>f(n) =&nbsp;θ(g(n))：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_ff6fc7e53dd6e8290535c5087daa811f.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\iff f(n)=O(g(n))\&\&f(n)=\Omega(g(n))" title="\iff f(n)=O(g(n))\&\&f(n)=\Omega(g(n))" /></span><script type='math/tex'>\iff f(n)=O(g(n))\&\&f(n)=\Omega(g(n))</script>；f的阶<strong>等于</strong>g的阶。</li>
<li>f(n) =&nbsp;o(g(n))：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_d1b4a70b18a5ceb6f5e06d26f31e871f.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\forall\varepsilon > 0,\exists n_0\in \mathbb{N},\forall n\geq n_0,f(n)/g(n) < \varepsilon" title="\forall\varepsilon > 0,\exists n_0\in \mathbb{N},\forall n\geq n_0,f(n)/g(n) < \varepsilon" /></span><script type='math/tex'>\forall\varepsilon > 0,\exists n_0\in \mathbb{N},\forall n\geq n_0,f(n)/g(n) < \varepsilon</script>；f的阶<strong>低于</strong>g的阶。</li>
</ul>
<p>可见，记号O给出了函数f(n)在渐进意义下的上界（但不一定是最小的），相反，记号Ω给出的是下界（不一定是最大的）。如果上界与下界相同，表示f(n)和g(n)在渐进意义下是同阶的（θ），亦即复杂度一样。</p>
<p>列举一些常见的函数之间的渐进阶的关系：</p>
<ul>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_c5b52cddc99653067f70a6e29a7d3b7e.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\log n!=\Theta(n\log n)" title="\log n!=\Theta(n\log n)" /></span><script type='math/tex'>\log n!=\Theta(n\log n)</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_581768416c6a3d30a7c02b4b4f384172.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\log n^2=\Theta(\log n)" title="\log n^2=\Theta(\log n)" /></span><script type='math/tex'>\log n^2=\Theta(\log n)</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_55af7d374584ac7a46c2059bfb29728c.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\log n^2=O(\sqrt n)" title="\log n^2=O(\sqrt n)" /></span><script type='math/tex'>\log n^2=O(\sqrt n)</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_d65100de5696360de01037eecf87570d.gif' style='vertical-align: middle; border: none; ' class='tex' alt="n=\Omega(\log^2n)" title="n=\Omega(\log^2n)" /></span><script type='math/tex'>n=\Omega(\log^2n)</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_bc11bedb4bc04797b947ce4eedfad233.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\log^2n=\Omega(\log n)" title="\log^2n=\Omega(\log n)" /></span><script type='math/tex'>\log^2n=\Omega(\log n)</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_6d56d62889e5ac0a196e53b89ad47058.gif' style='vertical-align: middle; border: none; ' class='tex' alt="2^n=\Omega(n^2)" title="2^n=\Omega(n^2)" /></span><script type='math/tex'>2^n=\Omega(n^2)</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_6d15cb87b10860dc9c2e3428d7d63e85.gif' style='vertical-align: middle; border: none; ' class='tex' alt="2^n=O(3^n)" title="2^n=O(3^n)" /></span><script type='math/tex'>2^n=O(3^n)</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_176bdd004c507dbfa891a264491941f0.gif' style='vertical-align: middle; border: none; ' class='tex' alt="n!=o(n^n)" title="n!=o(n^n)" /></span><script type='math/tex'>n!=o(n^n)</script></li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_fb8e629665f0e004d224ac5a7288658c.gif' style='vertical-align: middle; border: none; ' class='tex' alt="2^n=o(n!)" title="2^n=o(n!)" /></span><script type='math/tex'>2^n=o(n!)</script></li>
</ul>
<p>有些人可能会把这几个记号跟算法的最坏、最好、平均情况复杂度混淆，它们有区别，也有一定的联系。</p>
<p>即使问题的规模相同，随着输入数据本身属性的不同，算法的处理时间也可能会不同。于是就有了最坏情况、最好情况和平均情况下算法复杂度的区别。它们从不同的角度反映了算法的效率，各有用处，也各有局限。</p>
<p>有时候也可以利用最坏情况、最好情况下算法复杂度来粗略地估计算法的性能。比如某个算法在最坏情况下时间复杂度为θ(n ^ 2)，最好情况下为θ(n)，那这个算法的复杂度一定是O(n&nbsp;^ 2)、Ω(n)的。也就是说n ^ 2是该算法复杂度的上界，n是其下界。</p>
<p>接下来看看Master定理。</p>
<p>有些算法在处理一个较大规模的问题时，往往会把问题拆分成几个子问题，对其中的一个或多个问题递归地处理，并在分治之前或之后进行一些预处理、汇总处理。这时候我们可以得到关于这个算法复杂度的一个递推方程，求解此方程便能得到算法的复杂度。其中很常见的一种递推方程就是这样的：</p>
<p>设常数a >= 1，b > 1，f(n)为函数，T(n)为非负整数，T(n) = a T(n / b) + f(n)，则有：</p>
<ol>
<li>若<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_e1b188c49bbe201724335461b82f6e10.gif' style='vertical-align: middle; border: none; ' class='tex' alt="f(n)=O(n^{\log_b a-\varepsilon}),\varepsilon > 0" title="f(n)=O(n^{\log_b a-\varepsilon}),\varepsilon > 0" /></span><script type='math/tex'>f(n)=O(n^{\log_b a-\varepsilon}),\varepsilon > 0</script>，那么<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_f2db6f4f64e1d9db88492c4e59993442.gif' style='vertical-align: middle; border: none; ' class='tex' alt="T(n)=\Theta(n^{\log_b a})" title="T(n)=\Theta(n^{\log_b a})" /></span><script type='math/tex'>T(n)=\Theta(n^{\log_b a})</script>。</li>
<li>若<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_51022d4b037efec477a14cab1b3793bb.gif' style='vertical-align: middle; border: none; ' class='tex' alt="f(n)=\Theta(n^{\log_b a})" title="f(n)=\Theta(n^{\log_b a})" /></span><script type='math/tex'>f(n)=\Theta(n^{\log_b a})</script>，那么<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_b0c6b15a135063689753aaa5ac66ec64.gif' style='vertical-align: middle; border: none; ' class='tex' alt="T(n)=\Theta(n^{\log_b a}\log n)" title="T(n)=\Theta(n^{\log_b a}\log n)" /></span><script type='math/tex'>T(n)=\Theta(n^{\log_b a}\log n)</script></li>
<li>若<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_abc62c8fe2a0cc116e130562ee92d546.gif' style='vertical-align: middle; border: none; ' class='tex' alt="f(n)=\Omega(n^{\log_b a+\varepsilon}),\varepsilon > 0" title="f(n)=\Omega(n^{\log_b a+\varepsilon}),\varepsilon > 0" /></span><script type='math/tex'>f(n)=\Omega(n^{\log_b a+\varepsilon}),\varepsilon > 0</script>，并且对于某个常数c < 1和充分大的n有<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_2b58885048f46421d1bae5b40b9f317e.gif' style='vertical-align: middle; border: none; ' class='tex' alt="a f(n/b)\leq c f(n)" title="a f(n/b)\leq c f(n)" /></span><script type='math/tex'>a f(n/b)\leq c f(n)</script>，那么<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_6efc7e1cbd2d7bbf05c97723c96b063e.gif' style='vertical-align: middle; border: none; ' class='tex' alt="T(n)=\Theta(f(n))" title="T(n)=\Theta(f(n))" /></span><script type='math/tex'>T(n)=\Theta(f(n))</script>。</li>
</ol>
<p>比如常见的二分查找算法，时间复杂度的递推方程为T(n) = T(n / 2) + θ(1)，显然有<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_5c428a2f15cd72faece44d37dcefbe61.gif' style='vertical-align: middle; border: none; ' class='tex' alt="n^{\log_b a}=n^0=\Theta(1)" title="n^{\log_b a}=n^0=\Theta(1)" /></span><script type='math/tex'>n^{\log_b a}=n^0=\Theta(1)</script>，满足Master定理第二条，可以得到其时间复杂度为T(n) = θ(log n)。</p>
<p>再看一个例子，T(n) = 9 T(n / 3) + n，可知<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_f7e79c94f434fcf5ce49228233aba20d.gif' style='vertical-align: middle; border: none; ' class='tex' alt="n^{\log_b a}=n^2" title="n^{\log_b a}=n^2" /></span><script type='math/tex'>n^{\log_b a}=n^2</script>，令ε取1，显然满足Master定理第一条，可以得到T(n) =&nbsp;θ(n ^ 2)。</p>
<p>来一个稍微复杂一点儿例子，T(n) = 3 T(n / 4) + n log n。<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_d28a0aa1464c5885fffcbc28771f29f5.gif' style='vertical-align: middle; border: none; ' class='tex' alt="n^{\log_b a}=O(n^{0.793})" title="n^{\log_b a}=O(n^{0.793})" /></span><script type='math/tex'>n^{\log_b a}=O(n^{0.793})</script>，取ε = 0.2，显然当c = 3 / 4时，对于充分大的n可以满足a * f(n / b) = 3 * (n / 4) * log(n / 4) <= (3 / 4) * n * log n = c * f(n)，符合Master定理第三条，因此求得T(n) =&nbsp;θ(n log n)。</p>
<p>运用Master定理的时候，有一点一定要<strong>特别注意</strong>，就是第一条和第三条中的ε必须<strong>大于零</strong>。如果无法找到大于零的ε，就不能使用这两条规则。</p>
<p>举个例子，T(n) = 2 T(n / 2) + n log n。可知<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_2b91e95d1bb4473cec1039e445fd58b2.gif' style='vertical-align: middle; border: none; ' class='tex' alt="n^{\log_b a}=n^1" title="n^{\log_b a}=n^1" /></span><script type='math/tex'>n^{\log_b a}=n^1</script>，而f(n) = n log n，显然不满足Master定理第二条。但对于第一条和第三条，也无法找到大于零的ε使得<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_3fd3e8595d0a05482113aebb9e9a6c9a.gif' style='vertical-align: middle; border: none; ' class='tex' alt="n \log n=O(n^{1-\varepsilon})" title="n \log n=O(n^{1-\varepsilon})" /></span><script type='math/tex'>n \log n=O(n^{1-\varepsilon})</script>或者<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_7892c177069b1e47031f5981f0744d55.gif' style='vertical-align: middle; border: none; ' class='tex' alt="n \log n=\Omega(n^{1+\varepsilon})" title="n \log n=\Omega(n^{1+\varepsilon})" /></span><script type='math/tex'>n \log n=\Omega(n^{1+\varepsilon})</script>，因此不能用Master定理求解，只能寻求别的方式求解。比如可以利用递归树求出该算法的复杂度为<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_43fbbf65ad581926b129bb70ecf486c0.gif' style='vertical-align: middle; border: none; ' class='tex' alt="T(n)=O(n \log^2{n})" title="T(n)=O(n \log^2{n})" /></span><script type='math/tex'>T(n)=O(n \log^2{n})</script>。简单的说一下计算过程：</p>
<p>递归树的建立过程，就像是模拟算法的递推过程。树根对应的是输入的规模为n的问题，在递归处理子问题之外，还需要n log n的处理时间。然后根据递推公式给根节点添加子节点，每个子节点对应一个子问题。这里需要两个子节点，每个节点处理规模为n / 2的问题，分别需要(n / 2) * log(n / 2)的时间。因此在第二层一共需要n * (log n - 1)的时间。第三层节点就是将第二层的两个节点继续分裂开，得到四个各需要(n / 4) * log(n / 4)时间的节点，总的时间消耗为n * (log n - 2)。依此类推，第k（设树根为k = 0）层有2 ^ k的节点，总的时间为n * (log n - k)。而且可以知道，这棵树总共有log n层（最后一层每个节点只处理规模为1的子问题，无须再分治）。最后将每一层消耗的时间累加起来，得到：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_d056b2992a256c464ac1face3e7f898d.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\sum_{k=0}^{\log n}{n(\log n-k)}=\frac{1}{2}n\log n(\log n + 1)=O(n\log^2{n})" title="\sum_{k=0}^{\log n}{n(\log n-k)}=\frac{1}{2}n\log n(\log n + 1)=O(n\log^2{n})" /></span><script type='math/tex'>\sum_{k=0}^{\log n}{n(\log n-k)}=\frac{1}{2}n\log n(\log n + 1)=O(n\log^2{n})</script></p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection-2.html' rel='bookmark' title='单次遍历，带权随机选取问题（二）'>单次遍历，带权随机选取问题（二）</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/algorithm-complexity-and-master-theorem.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>《塞尔达传说：黎明公主》攻略：第三章 深海鱼族的传说</title>
		<link>http://www.gocalf.com/blog/zelda-tp-ch3.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=zelda-tp-ch3</link>
		<comments>http://www.gocalf.com/blog/zelda-tp-ch3.html#comments</comments>
		<pubDate>Sat, 05 Nov 2011 02:13:14 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[游戏]]></category>
		<category><![CDATA[Game]]></category>
		<category><![CDATA[Twilight Princess]]></category>
		<category><![CDATA[Wii]]></category>
		<category><![CDATA[塞尔达传说]]></category>
		<category><![CDATA[游戏攻略]]></category>
		<category><![CDATA[黎明公主]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1342</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_logo.png" class="attachment-post-thumbnail wp-post-image" alt="tp_ch03_logo" title="tp_ch03_logo" /></div>第三章 深海鱼族的传说（最后的影之碎片）]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_logo.png" class="attachment-post-thumbnail wp-post-image" alt="tp_ch03_logo" title="tp_ch03_logo" /></div><h3>第三章 深海鱼族的传说（最后的影之碎片）</h3>
<h5>新的旅行</h5>
<p>回到卡卡里科村，林克遇见塔洛，他看到了林克的英雄之弓，又闹着要林克表演箭术，并要林克射中西北山丘房子顶上的一根木棒，就算是救世主。<span id="more-1342"></span></p>
<p>要看清那么远的物体也还是有点勉强，林克只好到商店买了一副鹰眼（Hawkeye），有了这个就能够看清楚远处的物体了。林克一箭射中目标，孩子们都非常佩服林克，并给了林克一片<a href="http://www.gocalf.com/blog/zelda-tp-heartpiece.html#H09">心之碎片</a>（射箭的时候不使用鹰眼才能得到心之碎片）。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_02.jpg"><div id="attachment_1351" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_02-700x560.jpg" alt="tp_ch03_02" title="tp_ch03_02" width="700" height="560" class="size-large wp-image-1351 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">买到了鹰眼</p></div></a></p>
<p>告别了孩子们，林克来到巴恩斯的炸弹商店，在这可以买到炸弹，利用它林克炸开村口泉水旁的一个石头，出现了一个山洞，林克进入后使用钢之靴潜入水中得到一个<a href="http://www.gocalf.com/blog/zelda-tp-heartpiece.html#H10">心之碎片</a>，出来后在炸开的山洞正上方还有一个巨石，使用炸弹箭将其炸开，会发现另一个<a href="http://www.gocalf.com/blog/zelda-tp-heartpiece.html#H11">心之碎片</a>。林克在村里做好了补给，准备继续去寻找失踪的伊莉娅。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_01.jpg"><div id="attachment_1350" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_01-700x560.jpg" alt="tp_ch03_01" title="tp_ch03_01" width="700" height="560" class="size-large wp-image-1350 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">拿到一个心之碎片</p></div></a></p>
<h5>死寂的王城</h5>
<p>走出卡卡里科村，林克来到海拉尔平原，经过艾尔丁大桥，没走多远，第三堵黑暗之墙前出现在林克面前，进入黑暗世界，不远处发现了伊莉娅留下的包裹，随后追随伊莉娅的气味，进入了海拉尔城堡（Hyrule Castle），跟着气味来到一间酒吧前，门是开着的。林克钻了进去，看到了伊莉娅，眼前还有一个陌生种族的病人，听到旁边的卫兵说这个可能是佐拉（Zora）族的后裔，通过他们的谈话还得知海利亚湖（Hylia Lake）是佐拉鱼人出没的地区，林克在桌子的地图上看到了海利亚湖的位置，既然伊莉娅安然无恙，那么就动身前往海利亚湖吧。来到海利亚大桥上，林克发现桥上撒满了火药，原来兽人们早就埋伏在了这里，兽人从两边点燃了火药，林克进退两难，底下又是海利亚湖，看来只有跳下去了，林克迅速把附近的箱子推到桥边，然后爬上去坠入了海利亚湖。</p>
<h4>海利亚湖</h4>
<h5>冰湖，母爱</h5>
<p>林克上岸后，来到一座奇怪的房屋前，听到房前的人说不远处有一个兽人弓箭手时常骚扰他，林克当然不会放过这个兽人弓箭手，看来这不是一个普通的弓箭手，他召唤来一只巨大的飞龙，骑到飞龙背上与林克周旋，就是这样林克也不会退缩，获胜后米德娜将飞龙驯服了。飞龙带着林克飞进了一个山洞，这里地势险要，稍不注意就会撞到峭壁上。飞出山洞，林克来到了佐拉河上游（Upper Zora’s River），这里的河床都结冰了，林克跳下河床，沿着冰川向东前进，随后米德娜会带着林克攀登上北边的冰川，到达冰川顶部后，进入最北边的洞穴。这里又遇到了三个黑暗使者，消灭后出现了这个地区的黑暗空洞。接下来来到已经被冰冻的佐拉王国，米德娜记起了死亡山上的一块炙热的巨石，传送回死亡山，米德娜发动魔法将巨石传送到佐拉王座处，炙热的巨石将整个冰河都融化了，随后佐拉女皇鲁特拉（Rutela）的亡魂出现，她向林克表示感谢，她还请求林克找到并解救王子拉里斯（Ralis），难道就是海拉尔城中那个正被伊莉娅照顾的佐拉人？女皇承诺如果林克完成任务的话，会赐予林克水中呼吸的能力。林克一路返回到海利亚湖，上岸后发现一个洞穴，林克进入后找到最后一个光之精灵，它将最后一个光之石交给林克。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_03.jpg"><div id="attachment_1352" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_03-700x560.jpg" alt="tp_ch03_03" title="tp_ch03_03" width="700" height="560" class="size-large wp-image-1352 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">完全结冰的海利亚湖</p></div></a></p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_04.jpg"><div id="attachment_1353" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_04-700x560.jpg" alt="tp_ch03_04" title="tp_ch03_04" width="700" height="560" class="size-large wp-image-1353 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">死亡山上炙热的巨石，利用它来融化湖水</p></div></a></p>
<h4>拉内鲁地区</h4>
<h5>再见影子虫</h5>
<p>林克又踏上了收集光之泪的旅程，在精灵之泉的右边道路上不远的地方就有一只，往北尽头处的湖边还有一只，南边的草丛中藏有一只，把草打掉就可以看到。林克向西边游去，在一个小半岛上也有一只，向海利亚湖的南边游去，上岸后林克发现灌木，在遇到阴影怪物的南边，在一排有空隙的石头中，来回跳跃，会发现一支正在挖洞的虫。米德娜告诉他可以在这里召唤之前被收服的飞龙，飞龙带着林克飞进之前的那个洞穴，整个洞穴里一共有四支小虫子，林克用感知可以轻松发现到处乱飞的虫，让飞龙撞击虫子收集光之泪（用Z键锁定目标，然后快速抓住，在飞行时不能转身，如果没有抓住所有虫子就回到河的尽头话，就不得不重来一次了）。来到佐拉河上游，林克看到这里的女主人正被虫子吓得发抖，消灭虫子后，林克在河对岸找到嚎叫之岩，记下金狼出现的位置后，林克继续收集光之泪。林克顺着河向佐拉原住地（Zora’s Domain）游去，在水域西边的斜坡上有一只，在湖东边靠近雪峰的冰峰道路旁，米德娜会帮助林克攀登上去，途中会有一只虫子，往回走在小梯子处转身向高处的岩石跳上，顺着小路林克来到佐拉王座，虫子就在左边的墙上，林克撞击墙壁惊动虫子，然后杀掉获得光之泪。林克回到佐拉河上游，东南角的水道有两个佐拉亡魂，他们会带林克进入水道，游出来到了海拉尔城的外边，进入城中，来到酒馆外面，打碎角落的箱子就能发现一只虫子。虫子消灭完了，但是光之泪还有一颗，会在哪里呢？此时米德娜会带林克来到最后一只虫子的地方——海利亚湖的正中间。这是一只巨大的母虫，看来她就是罪魁祸首，母虫全身带电的时候，没有办法攻击，林克只好先躲到水里等她冲下来，待其身上电消失后，林克跳到她身上一阵狂咬，没多久虫子就会倒在水里，林克跳到她身上发动群体攻击将其消灭，结束战斗后得到了最后的光之泪。最后一位光之精灵拉内鲁（Lanayru）也变回了原形，他告诉林克，这个世界本来就是黑暗与光明交替的世界，光明离不开黑暗，黑暗也离不开光明，一旦力量失去了平衡，这个世界就会陷入混乱。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_05.jpg"><div id="attachment_1354" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_05-700x560.jpg" alt="tp_ch03_05" title="tp_ch03_05" width="700" height="560" class="size-large wp-image-1354 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">光之精灵拉内鲁（Lanayru）向林克讲述这个世界光与影的故事</p></div></a></p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_06.jpg"><div id="attachment_1355" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_06-700x560.jpg" alt="tp_ch03_06" title="tp_ch03_06" width="700" height="560" class="size-large wp-image-1355 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">这是林克？</p></div></a></p>
<h5>护送马车</h5>
<p>林克暂时不能完全理解拉内鲁的话，不过林克知道此时他还有重任在身。变回人形的林克从精灵洞窟出来后，一直沿着桥走，到达一间屋子边，在这里花10元坐大炮去到湖的上端。上去后找路回到海拉尔城，城外可以遇到金狼，见到它后，不死勇士会再次出现教授林克新的绝技。进城后可以花点时间在王城里晃晃，之前有捉到金色虫子的话还可以去王城城下町的东南街道的虫子屋里换个更大的钱包。之后林克一路来到特尔玛（Telma）的酒馆，终于可以和伊莉娅团聚了，但是她确显得不那么高兴，原来拉里斯的状况很糟糕，不及时救治可能会有生命危险，特尔玛记起卡卡里科村有位医术高明的人，一定就是牧师雷那多了，准备好马车，护送的责任自然落到了林克身上，途中的桥上再次遇到兽人首领阻挡林克一行的去路，下场当然不会很好过，这次他穿上了盔甲，用剑砍是没辙了，不过林克的骑射技术也不是盖的，林克又一次将他打败。之后道路还比较忙碌，林克一边要防止飞鸟放炸弹（要用弓箭将它们清理干净，不然马车会不断的转圈），还要防止马车被兽人射手的火箭烧着（马车着火后，要及时用回力标灭火），最后林克安全将他们送到了卡卡里科村，王子得救了。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_07.jpg"><div id="attachment_1356" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_07-700x560.jpg" alt="tp_ch03_07" title="tp_ch03_07" width="700" height="560" class="size-large wp-image-1356 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">护送马车（感觉这里还挺难的，一定要要组织飞鸟放炸弹）</p></div></a></p>
<h5>潜水服</h5>
<p>此时佐拉女王应约出现，带着林克来佐拉王的墓穴，将佐拉之铠（Zora Armor）交给了林克，从此林克就可以在水中自由的呼吸行动了（摇杆上代表上浮，下代表下潜，A加速）。回到村中，来到巴恩斯的炸弹商店，他又研制出了新型的炸弹，这种炸弹可以在水里爆炸（要穿上铁鞋，脚沾地后才能使用），林克买下后马不停蹄地来到海利亚湖（可以炸开墓地湖中的石头走捷径），穿上佐拉之铠跳入湖中。林克游到水底，找到入口，但是被一个巨石堵住了，林克发现底下有一个裂缝，放个水炸弹将其炸开，水柱一下冲了出来，再放个水炸弹，借助水柱的冲力，炸弹会浮上去把巨石炸开，顺着洞一直往里游，林克来到了湖底神殿（Lakebed Temple）。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_08.jpg"><div id="attachment_1357" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_08-700x466.jpg" alt="tp_ch03_08" title="tp_ch03_08" width="700" height="466" class="size-large wp-image-1357 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">穿上潜水服，向湖底出发！</p></div></a></p>
<h4>湖底神殿迷宫</h4>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_09.jpg"><div id="attachment_1358" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_09-700x611.jpg" alt="tp_ch03_09" title="tp_ch03_09" width="700" height="611" class="size-large wp-image-1358 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">湖底神殿迷宫地图</p></div></a></p>
<p>来到海利亚湖底部找到一堵有岩石的墙壁，在下面的水泡中放置一枚水炸弹，随后水泡会把炸弹浮上去并把岩石炸开，然后就可以进入迷宫了。顺着水道一直游到尽头上岸后向北前进，爬上梯子向前跳抓住天花板上的机关打开通向北边的门。</p>
<p><strong>房间2：</strong>放出炸弹箭炸下天花板上的钟乳石使其落下，创造一条前进的路后朝北前进进入房间3。穿盔甲的怪物，要闪到后面才能伤害它，有了飞爪以后可以直接将它的甲夺走再杀。</p>
<p><strong>房间3：</strong>房间中间有一个可以转动的楼梯，目前没办法控制，只能先从东边或西边的出口出去。一开始从梯子下去，在底部朝右边走，一直走到屋子的南边，然后跳过去抓住黄色的机关，可以转动台阶。再上到上层，到屋子上层的东边，同样抓住机关，这下可以通过底面西边的门来到房间4了。注意东北面的箱子里有地图。</p>
<p><strong>房间4：</strong>用炸弹箭射下天花板上的钟乳石后，穿过隧道舷梯向右。通过岩石可以到达中央的石柱，可以看到附近还有一个钟乳石，往那边走，在箱子里能得到一把小钥匙，然后回到房间3，来到上层西边的门前，得到欧库，打开门进入房间5。</p>
<p><strong>房间5：</strong>天花板上有钟乳石，打下来后可以借助其爬到墙上的藤蔓上。然后看到开关，跳过去抓住将它打开，接着向西北面移动。在西面林克能看到破损的墙壁， 先不管它，通过门来到南面，在南面的门处的箱子内可以得到小钥匙。有了这个，回到刚才看到的破墙那，炸开就可以通向房间6。</p>
<p><strong>房间6：</strong>当林克到达水闸控制室这里，顺着屋子中间的洞来到北边。一路向前到达顶部的房间内，爬上梯子打开机关，开始放水。当水流入屋子后，可以直接跳进水中，找到水中心台子上的另一个机关，拉动机关让水流到房间3内。通过南面的门在水车下可以发现一个小精灵。</p>
<p><strong>房间4：</strong>房间内的第三层开始转动，跳上去通过北面的门到达房间7。</p>
<p><strong>房间7：</strong>这里有个装有小钥匙的箱子，拿到后返回房间4，通过转动的平台到达西面的门，从这里进入房间7，向前打开门可到达房间8。</p>
<p><strong>房间8：</strong>在尽头有个岩石阻挡了去路，换上负重靴，下到水中，在石头下安置水炸弹，即可通过并前往房间9。</p>
<p><strong>房间9：</strong>这里天花板上有一个小BOSS：青蛙。注意在他跳起来后地上的影子，躲开影子然后攻击他的舌头使其张开嘴，这时再向嘴里射炸弹箭便能将其消灭，并且还能得到道具飞爪（Clawshot）。用飞爪攻击屋子南面门上的机关使门打开后，回到房间3。</p>
<p><strong>房间3：</strong>用飞爪可以在房间中心的吊灯上发现<a href="http://www.gocalf.com/blog/zelda-tp-heartpiece.html#H13">心之碎片</a>，同样用飞爪也能在箱子内得到20卢比。然后到上层的西面使用飞爪击中机关，使楼梯转动，形成一个水渠，让进入房间的流水流向东面的出口。</p>
<p><strong>房间10：</strong>熟练运用飞爪不断爬高，到达上层的出口进入房间11（另外藤条也可以用飞爪抓）。</p>
<p><strong>房间11：</strong>利用飞爪朝东面移动进入房间12。</p>
<p><strong>房间12：</strong>一直前进沿着旋梯上到顶部，途中的断处可以用飞爪通过，之后跳到机关上开始放水。这里有个箱子可以用飞爪上去后取得指南针。返回房间10。用飞爪击打东面的机关，下到下面的平台上，从东面的门到达房间13。</p>
<p><strong>房间13：</strong>房间13有三条渠道，都通往南面。另外这里有2条路可以通往房间14，其中一条过去后发现拿不到钥匙，需要返回再朝左下游找到另一条路，接着可从上方跳到房间14并取得大钥匙，然后回到房间3水中台子上的通往最终房间的大门。</p>
<p><strong>BOSS战：</strong>水底兽——摩菲尔（Twilit Aquatic——Morpheel）</p>
<p>穿上钢之靴降到水底后会遇到摩菲尔，第一阶段的时候会见到象海葵一样的它，远离周围的触手并保持在飞爪射程之内，然后将在其触手内不断移动的眼球抓出来进行攻击，中途摩菲尔会释放一些炸弹鱼进行干扰，如果抓到炸弹鱼的话要迅速离开其爆炸范围，几次攻击之后摩菲尔会露出本体。此后脱掉钢之靴游到摩菲尔的上方，找准时机锁定Boss的额头，用飞爪抓住其头顶处的眼睛后进行攻击，三次之后就可战胜摩菲尔。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_10.jpg"><div id="attachment_1359" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_10-700x466.jpg" alt="tp_ch03_10" title="tp_ch03_10" width="700" height="466" class="size-large wp-image-1359 wp-caption alignnone" /><p class="wp-caption-text">湖底神殿迷宫中的机关</p></div></a></p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_11.jpg"><div id="attachment_1360" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_11-700x466.jpg" alt="tp_ch03_11" title="tp_ch03_11" width="700" height="466" class="size-large wp-image-1360 wp-caption alignnone" /><p class="wp-caption-text">BOSS：水底兽——摩菲尔（Twilit Aquatic——Morpheel）第一阶段</p></div></a></p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_12.jpg"><div id="attachment_1361" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/tp_ch03_12-700x466.jpg" alt="tp_ch03_12" title="tp_ch03_12" width="700" height="466" class="size-large wp-image-1361 wp-caption alignnone" /><p class="wp-caption-text">BOSS：水底兽——摩菲尔（Twilit Aquatic——Morpheel）现出原形</p></div></a></p>
<hr />
<p>参考：</p>
<ul style="padding-right: 40px; ">
<li><a href="http://wii.tgbus.com/glmj/gl/200611/20061129114849.shtml" target="_blank">《塞尔达传说：黄昏公主》图文全攻略</a>&nbsp;by WiiBbs 攻研部 Szh、三代鬼彻、天堂的翅膀</li>
<li><a href="http://www.cngba.com/thread-16520313-1-1.html" target="_blank">《塞尔达传说 黄昏公主》完美攻略研究</a> by www.cngba.com 鸡蛋</li>
<li><a href="http://tv.duowan.com/0710/57154029137.html" target="_blank">Wii《塞尔达传说：黎明公主》流程攻略</a></li>
</ul>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/zelda-tp-intro.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：剧情介绍'>《塞尔达传说：黎明公主》攻略：剧情介绍</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-characters.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：角色介绍'>《塞尔达传说：黎明公主》攻略：角色介绍</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch2.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：第二章 死亡山颠的咆哮'>《塞尔达传说：黎明公主》攻略：第二章 死亡山颠的咆哮</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch1.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：初章 英雄传说的扉页'>《塞尔达传说：黎明公主》攻略：初章 英雄传说的扉页</a></li>
<li><a href='http://www.gocalf.com/blog/check-udisk.html' rel='bookmark' title='U盘检测软件：ChipGenius，MyDiskTest'>U盘检测软件：ChipGenius，MyDiskTest</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/zelda-tp-ch3.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[《塞尔达传说：黎明公主》攻略]]></series:name>
	</item>
		<item>
		<title>适合码农玩的自动机编程游戏：Manufactoria（流水线编程）</title>
		<link>http://www.gocalf.com/blog/manufactoria.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=manufactoria</link>
		<comments>http://www.gocalf.com/blog/manufactoria.html#comments</comments>
		<pubDate>Thu, 03 Nov 2011 13:42:32 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[游戏]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[图灵机]]></category>
		<category><![CDATA[智力题]]></category>
		<category><![CDATA[益智游戏]]></category>
		<category><![CDATA[算法]]></category>
		<category><![CDATA[自动机]]></category>
		<category><![CDATA[解谜]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1314</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/manufactoria-logo.png" class="attachment-post-thumbnail wp-post-image" alt="manufactoria-logo" title="manufactoria-logo" /></div>前几天在Matrix67的博客里看到了这个益智小游戏：Manufactoria，抽空玩了玩，虽然关卡不算多，但非常有趣。

这是个程序设计类的游戏，感觉就像是个状态机吧（有限自动机？），从纸带上读取数据，具有分支和写数据的功能，利用简单的几种原件组装成一台可以识别特定模式或者完成指定运算的机器。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/manufactoria-logo.png" class="attachment-post-thumbnail wp-post-image" alt="manufactoria-logo" title="manufactoria-logo" /></div><p>前几天在<a href="http://www.matrix67.com/blog/" target="_blank">Matrix67</a>的博客里看到了这个益智小游戏：<a href="http://www.matrix67.com/blog/archives/3306" target="_blank">Manufactoria</a>，抽空玩了玩，虽然关卡不算多，但非常有趣。</p>
<p>这是个程序设计类的游戏，感觉就像是个状态机吧（有限自动机？），从纸带上读取数据，具有分支和写数据的功能，利用简单的几种元件组装成一台可以识别特定模式或者完成指定运算的机器。<span id="more-1314"></span></p>
<p>游戏的背景大概是一家工业机器人（Industrial Robotics）生产厂请你（机器人工程师，Robotics Engineer）来测试和修复他们制造的机器人，所谓的“测试”就是对机器人内部纸带上的红蓝色点进行检测，判断其是否满足指定的模式；“修复”就是对纸带上的红蓝色点进行处理或者运算，产生指定的结果。这个游戏还支持自定义关卡，看到过有人提出求最大公约数之类的问题。</p>
<p>不知道别人是怎么思考的，反正我是先画想好用什么算法，然后在纸上画状态图把细节尤其是边界条件考虑清楚，然后开始布局，通过验证之后再不断地优化（减少使用的元件数量）。</p>
<p>开头几关非常简单，玩了七八关之后，每开启新的一关就在想，这怎么可能实现啊，但解决了之后又发现其实很简单。主要还是开始没有适应它的这种工作方式吧。</p>
<p>我的建议是每个程序员都应该玩一下这个游戏，我甚至考虑可以把它用在第一轮面试上，跟candidate随便聊聊天，让他玩一两关看看他的思路如何。</p>
<p>Matrix67的这篇博客是一年多之前发的了，后来我又找到了这个游戏的<a href="http://pleasingfungus.com/" target="_blank">官方网站</a>（<a href="http://pleasingfungus.com/#!/Manufactoria">http://pleasingfungus.com/#!/Manufactoria</a>），发现游戏版本更新了，细节上有不少改进，增加了不少测试用例，统计出来的运行时间也有所变化（另外要注意的是，在新版本中如果想让两个传送带正交于某个方格，需要按Shift键，否则就会替换）。</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" height="480" width="640"><param name="quality" value="high" /><param name="movie" value="http://pleasingfungus.com/Manufactoria/Manufactoria.swf" /><embed height="480" pluginspage="http://www.macromedia.com/go/getflashplayer" quality="high" src="http://pleasingfungus.com/Manufactoria/Manufactoria.swf" type="application/x-shockwave-flash" width="640"></embed></object></p>
<p>（如果上面的Flash无法加载，可以尝试我在这里上传的：<a href="http://www.gocalf.com/blog/wp-content/uploads/2011/11/Manufactoria.swf" target="_blank">Manufactoria.swf</a>。）</p>
<p>分享一下我在各关的解法（进入一个关卡，点击磁盘图标，在文本框中粘贴解法代码即可；注意贴入的代码中的关卡序号不需要与当前所在的关卡序号一致，游戏会自动跳转到正确的关卡，除非你还没有激活那一关）。另外很多关卡都有无数种解法，我一般会尽量优化使之元件个数最少（比较测试时间没有太大意义，一旦下一个版本的测试用例变化，测试时间就不一样了）。</p>
<p>下面这张图是游戏当前版本（v1.30）的关卡分布图，为了方便查找，我特意用红色字体添加了关卡序号在每关图标的左上角处。其中第29到31关是隐藏关，要通过了第24关才能显示出来。</p>
<div id="attachment_1320" class="wp-caption alignnone" style="width: 666px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/11/manufactoria-main.png" alt="manufactoria-main" title="manufactoria-main" width="656" height="538" class="size-full wp-image-1320 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">Manufactoria主界面（添加了关卡序号）</p></div>
<p>我的各关卡解决方案（第30和31关没有时间优化了，其他关都是尽可能优化过的）：</p>
<pre><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">?lvl=1&amp;code=c12:6f3;c12:7f3;c12:8f3;<br />
?lvl=2&amp;code=c12:8f3;p12:6f2;c12:7f3;<br />
?lvl=3&amp;code=p12:5f3;c13:5f0;p11:6f2;c11:5f3;p11:8f2;c11:7f3;c11:9f3;c11:10f2;<br />
?lvl=4&amp;code=p12:6f3;c11:6f2;c12:7f3;c12:8f3;<br />
?lvl=5&amp;code=p12:4f3;c12:6f3;c12:7f3;c12:8f3;c12:9f3;c12:10f3;p11:4f6;p13:4f4;p11:5f6;p13:5f4;c12:5f3;<br />
?lvl=6&amp;code=c12:4f3;p12:5f2;p12:6f2;c12:8f3;c12:9f3;c12:10f3;p12:7f7;c13:7f0;c11:7f1;c11:6f1;c11:5f2;<br />
?lvl=7&amp;code=c12:8f3;c12:9f3;c12:10f3;c11:3f3;c11:6f1;c12:5f3;c12:6f3;c13:3f3;c13:6f1;c12:7f3;p12:4f3;p11:4f6;p11:5f0;p13:4f4;p13:5f2;<br />
?lvl=8&amp;code=p12:6f3;b11:6f3;r13:6f3;c11:7f2;c13:7f0;c12:7f3;c12:8f3;<br />
?lvl=9&amp;code=c12:7f3;c12:8f3;c12:9f3;p12:5f3;g11:5f2;y13:5f0;c12:6f3;<br />
?lvl=10&amp;code=g12:4f3;p12:5f3;b11:5f2;r13:5f0;y12:6f3;c12:7f3;c12:8f3;c12:9f3;c12:10f3;<br />
?lvl=11&amp;code=c12:8f3;c12:9f3;p12:5f3;p13:5f3;c11:5f2;c14:5f0;c12:6f3;c12:7f3;<br />
?lvl=12&amp;code=r12:4f3;r12:5f3;r12:6f3;c12:7f3;c12:8f3;c12:9f3;c12:10f3;<br />
?lvl=13&amp;code=c12:10f3;c12:11f3;c12:12f3;q12:2f7;y12:3f3;r12:4f2;c12:5f1;c12:7f3;c12:8f3;y13:2f0;q13:3f6;p13:4f6;q13:5f4;b13:6f3;q13:7f4;r13:8f1;b14:3f3;c14:4f0;c12:9f3;<br />
?lvl=14&amp;code=c12:10f3;c12:11f3;c12:12f3;q12:2f7;y12:3f3;c12:7f3;c12:8f3;y13:2f0;q13:3f6;q13:7f4;c14:4f0;c12:9f3;p13:4f2;r14:3f3;r13:6f3;b13:8f1;r12:4f2;q13:5f2;b14:5f1;<br />
?lvl=14&amp;code=c12:10f3;c12:11f3;c12:12f3;c12:8f3;c12:9f3;r12:4f3;p13:5f2;r13:7f3;q13:8f4;b13:9f1;b12:6f1;c12:5f2;q13:4f0;q13:6f4;q12:2f7;y13:2f0;y12:3f3;c13:3f1;<br />
?lvl=15&amp;code=c11:5f3;c13:5f3;c13:6f0;p11:11f3;c12:11f3;i11:12f7;c10:11f3;c10:12f2;p12:4f2;c12:3f3;c10:7f3;c10:8f2;c10:9f3;p11:7f3;c11:8f3;p11:9f3;c12:7f3;c12:8f0;c12:9f3;c12:10f0;c11:6f3;c12:6f0;c10:10f2;c11:10f3;p12:5f1;<br />
?lvl=16&amp;code=c12:4f3;p12:5f2;p12:6f3;c12:7f3;c12:8f3;c12:9f3;c12:10f3;p13:6f7;<br />
?lvl=17&amp;code=y12:4f3;c12:7f3;c12:8f3;c12:9f3;c12:10f3;p12:6f3;i12:5f7;p11:6f4;b11:7f1;p11:5f1;r10:5f2;q11:4f1;<br />
?lvl=18&amp;code=c10:4f2;b10:5f1;c11:4f2;p11:5f3;c12:4f3;p12:5f3;c13:4f0;p13:5f3;c14:4f0;r14:5f1;y12:3f3;q12:6f2;p12:7f3;p11:7f3;p13:7f3;y10:7f1;y14:7f1;c10:6f1;c14:6f1;c12:8f3;c12:9f3;c12:10f3;c12:11f3;<br />
?lvl=19&amp;code=c12:10f3;c12:11f3;c12:12f3;c12:6f3;c12:8f3;c12:9f3;g12:3f3;y12:4f3;q12:5f0;i12:2f7;c12:7f3;p15:3f3;b14:3f3;r16:3f3;c16:4f0;c15:4f0;y14:4f3;c13:5f0;q14:5f7;p14:6f1;r13:6f2;b15:6f0;c9:2f2;r9:3f1;c10:2f2;p10:3f1;c10:4f1;c10:5f1;c10:6f1;c11:2f2;b11:3f1;b11:4f0;p11:5f0;r11:6f0;b13:1f2;g13:2f2;p14:1f3;q14:2f1;r15:1f0;c15:2f3;<br />
?lvl=20&amp;code=c12:12f3;c12:6f3;c12:8f3;c9:2f2;r9:3f1;c10:2f2;p10:3f1;c10:4f1;c10:5f1;c10:6f1;c11:2f2;b11:3f1;b11:4f0;p11:5f0;r11:6f0;g12:3f3;y12:4f3;q12:5f0;i12:2f7;g13:2f2;q14:2f1;c15:2f3;p14:1f3;b13:1f2;r15:1f0;p15:3f3;b14:3f3;r16:3f3;c16:4f0;c15:4f0;y14:4f3;c13:5f0;q14:5f7;p14:6f1;r13:6f2;b15:6f0;y12:7f3;p11:7f7;p13:7f7;c11:8f1;c13:8f1;p12:9f3;q11:9f0;q13:9f6;p10:9f2;p14:9f0;r10:8f3;r14:10f1;b10:10f1;b14:8f3;q12:10f2;q12:11f2;<br />
?lvl=21&amp;code=c12:7f3;c12:8f3;c12:9f3;c12:10f3;c12:11f3;c12:12f3;c12:6f3;p12:3f3;c12:4f3;c12:5f3;y12:2f3;r8:2f2;p9:2f1;p9:3f4;b9:4f1;b10:1f3;p10:2f6;i10:3f1;c11:3f0;q11:2f1;<br />
?lvl=22&amp;code=c12:11f3;c12:12f3;c12:9f3;c12:10f3;c10:5f2;c10:7f1;g11:2f2;p11:3f0;y11:4f1;q11:6f7;q11:8f7;p12:3f3;c12:5f3;q12:6f7;q12:8f7;y13:3f0;q13:6f7;q13:8f7;c14:5f0;c14:7f1;c12:2f3;r12:4f3;r14:8f1;r10:8f1;p12:7f0;g10:6f1;c11:5f2;c13:5f0;y14:6f1;<br />
?lvl=23&amp;code=c12:12f3;c12:10f3;c12:11f3;c12:9f3;p12:4f3;p10:4f2;r10:3f3;b10:5f1;p14:4f0;r14:5f1;b14:3f3;c12:8f3;c11:3f2;c13:3f0;p12:6f3;b11:6f2;r13:6f0;y12:3f3;g12:2f3;g13:5f2;g11:5f0;q13:4f6;q11:4f0;q12:5f6;q12:7f2;<br />
?lvl=24&amp;code=c12:9f3;c12:10f3;c12:11f3;c12:6f3;c12:7f3;c12:8f3;c12:12f3;b10:3f3;c10:4f2;r10:5f1;p11:4f6;q11:5f4;y12:3f3;p12:4f3;c12:5f3;p13:4f4;q13:5f2;r14:3f3;c14:4f0;b14:5f1;q13:3f6;q11:3f0;c12:2f3;c11:2f2;c13:2f0;<br />
?lvl=25&amp;code=y12:5f3;p12:6f3;r11:6f2;b13:6f0;q12:7f2;c12:8f3;c12:9f3;<br />
?lvl=26&amp;code=y12:5f3;p12:6f3;c13:6f0;b11:6f2;q12:7f2;c12:8f3;c12:9f3;<br />
?lvl=27&amp;code=c12:10f3;g12:4f3;y12:5f3;p12:6f3;b11:6f2;q13:6f6;p14:6f0;b14:5f3;c13:5f0;r14:7f1;g13:7f2;q12:7f6;p12:8f3;b11:8f2;r13:8f0;q12:9f2;<br />
?lvl=28&amp;code=y12:3f3;c12:9f3;c12:10f3;c12:11f3;q11:5f5;p12:5f3;q13:5f1;c12:4f3;b11:4f2;r13:4f0;y10:5f3;y14:5f3;c10:6f2;c14:6f0;b11:6f2;r13:6f0;p12:6f3;c12:8f3;q12:7f2;<br />
?lvl=29&amp;code=p12:5f3;c12:9f3;c12:10f3;c12:11f3;p11:3f1;c11:4f1;q11:5f4;p13:3f1;c13:4f1;q13:5f2;r10:4f3;p10:5f2;b10:6f1;b14:4f3;p14:5f0;r14:6f1;q12:6f0;q12:7f0;c12:8f3;g12:3f3;c12:4f3;<br />
?lvl=30&amp;code=c12:4f3;g14:5f3;q11:5f1;q13:5f5;c14:7f3;q15:8f5;q13:8f1;g12:8f3;g16:8f3;c11:9f3;c13:9f3;c15:10f0;c14:10f0;c12:10f3;c12:12f2;c13:12f2;c14:12f2;c15:12f2;c16:12f2;c17:12f2;c18:12f1;c18:11f1;c18:10f1;c18:9f1;c18:8f1;c18:7f1;c18:6f1;c18:5f1;c18:4f1;c18:3f0;c17:3f0;c16:3f0;c15:3f0;c14:3f0;c13:3f0;q12:11f7;p12:5f7;c11:6f0;c14:6f3;p14:8f3;b13:7f2;r15:7f0;q12:9f3;g13:10f0;y11:10f2;b13:4f0;r11:4f2;q12:6f7;c14:9f2;c15:9f1;q16:10f3;c16:9f3;c17:10f3;c17:11f0;c16:11f0;c15:11f1;c9:12f2;c10:11f3;p10:12f7;q10:13f3;c11:11f0;q11:13f3;c6:9f3;c6:10f2;g7:8f3;q7:9f3;c7:10f2;b8:7f2;q8:8f1;c9:5f3;g9:6f3;c9:7f3;p9:8f3;c10:6f0;r10:7f0;q10:8f5;c9:9f2;c10:9f1;c11:8f2;c8:10f2;c9:10f2;c10:10f2;c8:9f3;g12:2f0;y11:2f3;c11:3f2;c12:3f3;c10:5f0;<br />
?lvl=31&amp;code=c18:5f1;c18:4f1;c18:3f0;c17:3f0;c16:3f0;c15:3f0;c14:3f0;r13:2f3;g12:2f2;g13:3f0;c12:3f0;p10:3f0;c11:3f0;q10:2f2;q10:4f6;r11:4f1;b11:2f3;g10:1f0;g10:5f2;i9:4f7;b6:8f3;g7:7f3;p7:8f3;b8:6f2;q8:7f1;b8:8f3;c9:6f3;p9:7f3;c9:8f2;r10:6f0;q10:7f5;c10:8f1;c11:7f2;b11:8f3;g12:7f3;p12:8f3;b13:6f2;q13:7f1;r13:8f3;c14:6f3;p14:7f3;c14:8f2;c14:9f0;r15:6f0;q15:7f5;c15:8f1;r15:9f0;g16:7f3;c16:8f3;c9:5f3;c11:5f2;c12:5f2;c13:5f2;c14:5f3;p15:10f0;r15:11f0;c16:9f3;c16:10f0;b6:11f2;p7:11f3;q7:12f3;r8:11f0;c8:12f2;q9:12f5;c7:10f3;r14:11f1;c14:10f0;c13:10f0;c12:10f0;c11:10f0;c10:10f0;c9:10f0;c8:10f0;b13:9f3;r11:9f3;c9:11f2;c10:11f2;c11:11f2;c12:11f2;c13:11f3;i13:12f5;c13:13f2;c14:13f2;c15:13f2;c16:13f2;c17:13f2;c18:13f1;c18:12f1;c18:11f1;c18:10f1;c18:9f1;c18:8f1;c18:7f1;c18:6f1;q10:12f6;c10:13f2;c11:13f2;g11:12f2;c14:12f2;c15:12f2;c16:12f2;c17:12f1;c17:11f1;c17:10f1;c17:9f1;c17:8f1;c17:7f1;c17:6f1;c17:5f0;c16:5f0;c15:5f0;g12:12f2;r8:9f3;b6:9f3;c6:10f2;i9:3f6;c8:4f2;c9:1f3;c9:2f3;c8:3f3;</div></div></pre>
<p>～～～～～～～～～～ 分隔符&nbsp;～～～～～～～～～～</p>
<p>以下内容有剧透，三思而后看。</p>
<p>～～～～～～～～～～ 分隔符&nbsp;～～～～～～～～～～</p>
<p>Level 1: Robotoast! ACCEPT: Move robots from the entrance (top) to the exit (bottom)!</p>
<p>没有任何悬念，用3个元件，耗时32764（注意这是v1.30里的计时单位，在老版本中大概是0:02）。</p>
<p>Level 2: Robocoffee! If a robot's string starts with blue, accept. Otherwise, reject!</p>
<p>要求接受以蓝色开头的机器人。也没有任何可以商量的，3个元件，耗时24572。</p>
<p>Level 3: Robolamp! ACCEPT: if there are three or more blues!</p>
<p>要求接受纸带中有至少3个蓝点的机器人。8个元件，112570时间。</p>
<p>Level 4: Robofish! ACCEPT: if a robot contains NO red!</p>
<p>要求接受没有红点的机器人。4个元件，32764时间。</p>
<p>Level 5: Robobugs! ACCEPT: if the tape has only alternating colors!</p>
<p>如果纸带上的颜色是交替出现的（没有连续的红色或蓝色）就接受。6个元件，32900时间。</p>
<p>Level 6: Robocats! ACCEPT: if the tape ends with two blues!</p>
<p>如果最后两个颜色是蓝色则接受。11个元件，182272时间。</p>
<p>Level 7: Robobears! ACCEPT: Strings that begin and end with the same color!</p>
<p>如果第一个和最后一个色点颜色相同则接受。注意没有色点和只有一个色点这两种特殊情况。15个元件，176136时间。</p>
<p>Level 8: RC Cars! OUTPUT: The input, but with the first symbol at the end!</p>
<p>把第一个色点放到最后去。7个元件，49144时间。</p>
<p>Leve 9: Robocars! OUTPUT: Replace blue with green, and red with yellow!</p>
<p>把蓝色和红色分别换成了绿色和黄色。7个元件，229374时间。</p>
<p>Level 10: Robostilts! OUTPUT: Put a green at the beginning and a yellow at the end!</p>
<p>在色带的最前端放一个绿色，末尾处放一个黄色。毫无悬念，9个元件，53244时间。</p>
<p>Level 11: ACCEPT: With blue as 1 and red as 0, accept odd binary strings!</p>
<p>只接受奇数数字，也就是最后一位是蓝色的。至于空色带就无所谓了，严格来讲应该是不接受，但至少这个版本里没有这样的测试数据。8个元件，167931时间。</p>
<p>Level 12: Soldiers! OUTPUT: With blue as 1 and red as 0, multiply by 8!</p>
<p>要把输入的数字乘以8，程序员对这个应该是得心应手了，再末尾添加三个0（红色）即可。7个元件，65520时间。</p>
<p>Level 13: Officers! OUTPUT: With blue as 1 and red as 0, add 1 to the binary string!</p>
<p>给输入的数字做加1操作。开始的时候感觉是无法完成的，但仔细想想就很简单。加1操作，从二进制的角度来看，就是把末尾的1都变成0，最后一个0变成1。主要的难点是要从最后一位往前加，所以要不端地循环，每次都处理最后一个没有处理过的色点。另外在优化的时候发现，可以先把末尾的1变成黄色，这样就不需要再另外使用分隔符号了。分隔符用来标记字串的中止以及当前处理到的位置。</p>
<p>19个元件，81580时间。</p>
<p>Level 14: Generals! OUTPUT: Substract 1 from the binary string! (Input >= 1)</p>
<p>减1操作，跟第13关其实是一样的，红色和蓝色互换就好了。19个元件，79750时间。</p>
<p>但这一关还可以再稍微调整一下布局，变成18个元件，81686时间。</p>
<p>Level 15: Robotanks! ACCEPT: With blue as 1 and red as 0, accept binary strings > 15!</p>
<p>要求接受大于15的数字。也就是要求大于或等于16，即1后面至少有四个二进制位。于是就是要判断第一个蓝色后面是否至少有四个色点，不论颜色。25个元件，19958时间。</p>
<p>Level 16: Robospies! ACCEPT: With blue as 1 and red as 0, accept natural powers of four!</p>
<p>要求接受4的幂，也就是第一个蓝色后面必须恰好有偶数（包括0）个红色色点。注意要忽略掉开头的红色。8个元件，57372时间。</p>
<p>Level 17: Androids! ACCEPT: Some number of blue, then the same number of red!</p>
<p>要求纸带上的色点必须是若干个蓝色后面跟着同样数量的红色。开始也是觉得很难，主要是没有办法计数。当然解决办法就是一次一次循环，每次循环中判断一对红蓝色点。对于这种需要循环处理的问题，我一般都用一个黄色作为分隔符作为字符串的终结标记。12个元件，63041时间。</p>
<p>Level 18: Robo-children! ACCEPT: An equal number of blue and red, in any order!</p>
<p>判断色带上蓝色和红色的数量是否恰好相等。依旧是每次循环检查一对。23个元件，266582时间。</p>
<p>Level 19: Police! OUTPUT: Put a yellow in the middle of the (even-length) string!</p>
<p>输入的色带上有偶数个色点（不用判断是否满足），要求在中间位置插入一个黄色。这一关开始想了好久，排满了整个棋盘才搞定，后来一直优化到40个元件。想到了两种方案，一种是在颜色串的首尾各放一个色点，每次循环的时候让两个色点分别向中间移动一格，直到二者相遇。另一种是用起始位置放两个色点，每次循环的时候一个色点往后移动一格，另一个色点往后移动两个。我最后的优化版是采用第二种方法的。40个元件，291584时间。</p>
<p>如果输入的色带上有奇数个色点，那我的算法会在中间色点的后方插入黄色。</p>
<p>Level 20: Judiciary! ACCEPT: (Even-length) strings that repeat midway through!</p>
<p>判断色带上的色点（偶数个）是否恰好前半部分与后半部分的排列完全一样。比如如果前半部分是红蓝红红蓝，后半部分也必须是红蓝红红蓝。这一关我是直接利用了第19关和第29关（恰好我是先完成了第29关才回过头玩的这关），即先给这个颜色串的中间位置添加一个黄色（直接照搬第19关的布局），然后利用第29关的布局判断黄色分割的两个子串是否完全一致。</p>
<p>52个元件，319428时间。</p>
<p>Level 21: Teachers! ACCEPT: X blue, then X red, then X more blue, for any X!</p>
<p>要求色带上恰好是有若干个蓝色，跟着同样数目的红色和另外同样数目个蓝色。也可以是一个色点都没有。跟第17关的算法完全一样，只要再考虑考虑布局即可。</p>
<p>20个元件，76590时间。</p>
<p>Level 22: Politicians! ACCEPT: If there are exactly twice as many blues as red!</p>
<p>判断色带上蓝色是否恰好是红色的两倍。这一关其实跟第18关没有太大区别，一个简单高效的解决办法就是先把蓝色减半，然套用第18关的布局来检测减半后的蓝色是否与红色数目相等。</p>
<p>给蓝色减半的时候，比较传统的办法是用一个黄色作为色串终止符，从头开始，每读到一个红色就写一个红色，读到两个蓝色之后写一个蓝色。或着稍微变化一下，不用额外的黄色作终止符，而是在遍历的时候直接用黄色替换红色，用一个绿色替换两个蓝色。</p>
<p>用29个元件，296870时间。</p>
<p>Level 23: Academics! OUTPUT: Reverse the input string!</p>
<p>把输入的颜色串反转。基本的方法就是把第一个色点放到色串的最后，再把第二个色点放到倒数第二位。除了用一个黄色标记色串的终止外，在用一个绿色分割尚未处理的色串和部分反转了的色串。</p>
<p>用25个元素，227328时间。</p>
<p>Level 24: Engineers! ACCEPT: Perfectly symmetrical strings!</p>
<p>判断颜色串是否是对称的。也比较简单啦，每次用第一个色点做分支，在每个分支里判断最后一个色点，如果跟第一个一样则继续，否则丢弃。用25个元件，47696时间。</p>
<p>Level 25: Roborockets! OUTPUT: Swap blue for red, and red for blue!</p>
<p>把红蓝颜色互换。毫无悬念，7个元件，229374时间。</p>
<p>Level 26: Roboplanes! OUTPUT: All of the blue, but none of the red!</p>
<p>保留输入中的所有蓝色，丢掉红色。跟第25关唯一的区别就是遇到红色后不再写回到色带上。7个元件，22526时间。</p>
<p>Level 27: Rocket Planes! OUTPUT: The input, but with all blues moved to the front!</p>
<p>把输入中的蓝色都移动到红色的前面。</p>
<p>这一关有点儿意思，我最后设计的方法是直接利用第23关反转输入的方法。在第23关的布局中，中轴线左边是针对第一个是蓝色的处理，右边是针对第一个是红色的处理。在这一关里依旧保留右半边，但把左半边改成遇到蓝色就直接写一个蓝色回去。最后的效果就是不断地把红色往最后写，直到红色全都聚集到后半部分。</p>
<p>用16个元件，12390时间。</p>
<p>Level 28: Robomecha! OUTPUT: The input, but with the last symbol moved to the front!</p>
<p>把最后一个色点放到最前面。很简单，19个元件，606214时间。</p>
<p>Level 29: Seraphim! ACCEPT: Two identical strings, separated by a green!</p>
<p>判断由绿色点分开的两个色串是否完全相等。也挺简单的，补一个绿色作为终止符，取出色串一的第一个颜色，把其他的写回纸带，判断色串二的第一个颜色跟它是否一样；这时候两个色串都去掉了第一个颜色，而且刚好色串二跟色串一交换了顺序，再重复用同样的方法判断下去即可。21个元件，166182时间。</p>
<p>Level 30: Ophanim! ACCEPT: Read the tape as two numbers, A and B, split by a green: accept if A > B!</p>
<p>由绿色点分开的两个色串，从二进制数字的角度判断是否前一个数大于后一个数。</p>
<p>我用的方法是求B - A，当然不用记录完整的结果，只要记录借位状态即可。不过我没有再进行优化，现在用了88个元件，60617时间。估计能优化掉一小半的元件。</p>
<p>Level 31: Metatron! OUTPUT: Read the tape as two numbers, A and B, split by a green: output A + B!</p>
<p>计算被绿色分开的两个数字之和。基本上就是从最低位逐位加上去。同样是还没有优化，应该能减少一半以上的元件。现在用120个元件，108630时间。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/manufactoria.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>求内积最大的子数组</title>
		<link>http://www.gocalf.com/blog/max-inner-product.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=max-inner-product</link>
		<comments>http://www.gocalf.com/blog/max-inner-product.html#comments</comments>
		<pubDate>Sat, 29 Oct 2011 15:09:28 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Google面试]]></category>
		<category><![CDATA[数组内积]]></category>
		<category><![CDATA[最大值问题]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1291</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/max_inner_prod.png" class="attachment-post-thumbnail wp-post-image" alt="max_inner_prod" title="max_inner_prod" /></div>问题描述：有两个长度均为 n 的整数数组 A 和 B，现在要从这两个数组中各抽出 s 个数字，分别构成两个新的数组 C 和 D，要求数组 C 和 D 的内积最大。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/max_inner_prod.png" class="attachment-post-thumbnail wp-post-image" alt="max_inner_prod" title="max_inner_prod" /></div><p>之前在网上看到有好多人在讨论这道题，据说是一道Google的面试题。</p>
<p>问题描述：有两个长度均为 n 的整数数组 A 和 B，现在要从这两个数组中各抽出 s 个数字，分别构成两个新的数组 C 和 D，要求数组 C 和 D 的内积最大。<span id="more-1291"></span></p>
<p>用数学语言描述一下题目，就是已知：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_1b3c0c060cc898a3951587aa7349add2.gif' style='vertical-align: middle; border: none; ' class='tex' alt="A=\left[a_1,a_2,\cdots,a_n\right]" title="A=\left[a_1,a_2,\cdots,a_n\right]" /></span><script type='math/tex'>A=\left[a_1,a_2,\cdots,a_n\right]</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_387273853e973daf36f7d6a212311f74.gif' style='vertical-align: middle; border: none; ' class='tex' alt="B=\left[b_1,b_2,\cdots,b_n\right]" title="B=\left[b_1,b_2,\cdots,b_n\right]" /></span><script type='math/tex'>B=\left[b_1,b_2,\cdots,b_n\right]</script>；</p>
<p>求：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_35fd45a270e668385680d436a4eebbad.gif' style='vertical-align: middle; border: none; ' class='tex' alt="C=\left[c_1,c_2,\cdots,c_s\right]" title="C=\left[c_1,c_2,\cdots,c_s\right]" /></span><script type='math/tex'>C=\left[c_1,c_2,\cdots,c_s\right]</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_8ecf921c724ff1ae98cad66f7f222369.gif' style='vertical-align: middle; border: none; ' class='tex' alt="D=\left[d_1,d_2,\cdots,d_s\right]" title="D=\left[d_1,d_2,\cdots,d_s\right]" /></span><script type='math/tex'>D=\left[d_1,d_2,\cdots,d_s\right]</script>，满足：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_015bf75b25e2bdd29cef96a54090ab08.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\forall c_i\in C,c_i\in A" title="\forall c_i\in C,c_i\in A" /></span><script type='math/tex'>\forall c_i\in C,c_i\in A</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_7cf6978eff7de136c8a1097a5d29e63a.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\forall d_i\in D,d_i\in B" title="\forall d_i\in D,d_i\in B" /></span><script type='math/tex'>\forall d_i\in D,d_i\in B</script>；</p>
<p>要使得 C、D 的内积（<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_eb2eaea61a542fe194c0a81c89246707.gif' style='vertical-align: middle; border: none; ' class='tex' alt="C\cdot D=c_1d_1+c_2d_2+\dots+c_sd_s" title="C\cdot D=c_1d_1+c_2d_2+\dots+c_sd_s" /></span><script type='math/tex'>C\cdot D=c_1d_1+c_2d_2+\dots+c_sd_s</script>）最大。</p>
<p>一、先考虑只有正数的情况：</p>
<p>当 s = 1 时，题目就退化成，从 n 个正整数中选取一个，从另外 n 个正整数中选取一个，使得乘积最大。显然，两次选取的都应该是那些数中最大的。</p>
<p>当 s > 1 时，我们分两步考虑，先考虑选取哪些数，再考虑这些数怎么配对。</p>
<p>1. 相信很多人都可以轻松地得出这样的结论：从 A 中选取最大的 s 个数构成 C，从 B 中选取最大的 s 个数构成 D，才有可能使得 C、D 内积最大。因为如果用A中的某个较小的数替换 C 中的任何一个数字，都会导致对应的乘积变小，从而整个内积变小。对于 D 也是类似的。</p>
<p>2. 对于选定的 C 和 D，如何配对呢？显然，应该让 C 中最大的数与 D 中最大的数相乘，C 中第二大的数与 D 中第二大的数相乘，以此类推。这个命题的证明也是很简单的，考虑任意两对数字：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_3bdc0cee503d8864fe72a161ce81fdb4.gif' style='vertical-align: middle; border: none; ' class='tex' alt="c_i\leq c_j" title="c_i\leq c_j" /></span><script type='math/tex'>c_i\leq c_j</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_e2773e609c3fd1ff9715983f6ddee9de.gif' style='vertical-align: middle; border: none; ' class='tex' alt="d_k\leq d_l" title="d_k\leq d_l" /></span><script type='math/tex'>d_k\leq d_l</script>，显然有</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_32b73074bc1a8070935d792d17032206.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{array}{cl} & (c_id_k+c_jd_l)-(c_id_i+c_jd_k) \\ = & c_i(d_k-d_l)-c_j(d_k-d_l) \\ = & (c_i-c_j)(d_k-d_l) \\ \geq & 0 \end{array}" title="\begin{array}{cl} & (c_id_k+c_jd_l)-(c_id_i+c_jd_k) \\ = & c_i(d_k-d_l)-c_j(d_k-d_l) \\ = & (c_i-c_j)(d_k-d_l) \\ \geq & 0 \end{array}" /></span><script type='math/tex'>\begin{array}{cl} & (c_id_k+c_jd_l)-(c_id_i+c_jd_k) \\ = & c_i(d_k-d_l)-c_j(d_k-d_l) \\ = & (c_i-c_j)(d_k-d_l) \\ \geq & 0 \end{array}</script></p>
<p>因此，如果 A、B 全部都是正整数，那只需要分别排序后，从大到小选取 s 个数即可。</p>
<p>二、接下来考虑只有负数的情况：</p>
<p>只有负数跟只有正数是类似的，因为两个负数相乘的结果与这两个负数的<strong>绝对值</strong>相乘是一样的。根据上面的分析，我们只要对 A、B 分别排序后，从小到大（即<strong>绝对值</strong>从大到小）选取 s 个数即可。</p>
<p>三、再考虑两个数组一个全是正数，另一个全是负数的情况：</p>
<p>不妨设 A 中全是正数，B 中全是负数。</p>
<p>当 s = 1 时，题目就退化成，从 n 个正整数中选取一个，从另外 n 个负整数中选取一个，使得乘积最大。显然，两次选取的都应该是那些数中<strong>绝对值</strong>最小的（即最小的正数和最大的负数）。</p>
<p>当 s > 1 时，还是分两步考虑。</p>
<p>1. 很容易证明，应该从两个数组中分别选取<strong>绝对值</strong>最小的 s 个数（即正数数组中最小的 s 个数，负数数组中最大的 s 个数）。因为如果剩余的任何数字替换进来，都会导致对应的乘积的绝对值变大，乘积本身变小，从而整个内积变小。值得注意的是，很多人在这里容易出错，他们没有考虑到乘积为负数时，绝对值越大，乘积本身越小。</p>
<p>2. 对于选定的 C 和 D，如何配对呢？根据上面【一、2.】中的式子可以知道，我们还是要让最大的那对数相乘，第二大的那对数相乘，……。这里需要注意，也是很多人容易出错的地方，最大的那对数是正数中的最大值（绝对值也最大）和负数中的最大值（绝对值最小）。与全是正数时不同的一点是，两个数组都是正数时，最大的那对数的乘积恰好也是最大的；但一正一负的时候，最大的那对数的乘积并不一定是最大，最小的一对数的乘积也不一定是最小，但他们累加起来一定是最大的。比如 [1, 2] 和 [-1, -2]，正确的配对应该是<code class="codecolorer text geshi"><span class="text">2 * -1 + 1 * -2 = -4</span></code>，而不是<code class="codecolorer text geshi"><span class="text">1 * -1 + 2 * -2 = -5</span></code>。</p>
<p>四、几种特殊情况都考虑完了，最后就是正负数任意混合的一般情况。根据上面的分析，我们终归是要对 A 和 B 分别排序的，排序之后将两个数组的下标对齐，可以将两个数组分成三个部分，第一个部分中两个的数组元素都是负数（负数部分），第二个部分中一个数组元素都是负数而另一个都是正数（异号部分），第三个部分中两个数组的元素都是正数（正数部分），如下所示：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_af92b0d7fe8b0fd6f1d98afddab39810.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{matrix} A:&[&-&|&+&|&+&]\\ B:&[&-&|&-&|&+&] \end{matrix}" title="\begin{matrix} A:&[&-&|&+&|&+&]\\ B:&[&-&|&-&|&+&] \end{matrix}" /></span><script type='math/tex'>\begin{matrix} A:&[&-&|&+&|&+&]\\ B:&[&-&|&-&|&+&] \end{matrix}</script></p>
<p>由于负数部分和正数部分都产生正的乘积，我们需要同时考虑这两个部分。每次从这两个部分各选出<strong>绝对值</strong>最大的一对数，将乘积更大的那对从 A、B 中转移到 C、D 中，然后继续比较。</p>
<p>如果负数部分和正数部分都取完了，还缺 m 对数，那就从异号部分选取最小的 m 个正数，和最大的 m 个负数，对应配对即可。</p>
<p>算法示意：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> MinInnerProduct<span style="color: black;">&#40;</span>A<span style="color: #66cc66;">,</span> B<span style="color: #66cc66;">,</span> n<span style="color: #66cc66;">,</span> s<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>A<span style="color: black;">&#41;</span> <span style="color: #66cc66;">==</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>B<span style="color: black;">&#41;</span> <span style="color: #66cc66;">==</span> n <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff4500;">0</span> <span style="color: #66cc66;">&lt;=</span> s <span style="color: #66cc66;">&lt;=</span> n:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">Exception</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Invalid arguments.'</span><span style="color: black;">&#41;</span><br />
<br />
&nbsp; A.<span style="color: black;">sort</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; B.<span style="color: black;">sort</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: black;">&#40;</span>C<span style="color: #66cc66;">,</span> D<span style="color: #66cc66;">,</span> <span style="color: #008000;">sum</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: black;">&#40;</span>i<span style="color: #66cc66;">,</span> j<span style="color: black;">&#41;</span> <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> n - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><br />
<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>C<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&lt;</span> s:<br />
&nbsp; &nbsp; val1 <span style="color: #66cc66;">=</span> A<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span> * B<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; val2 <span style="color: #66cc66;">=</span> A<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span> * B<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> val1 <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">0</span> <span style="color: #ff7700;font-weight:bold;">and</span> val2 <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">0</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">break</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> val1 <span style="color: #66cc66;">&gt;=</span> val2:<br />
&nbsp; &nbsp; &nbsp; C.<span style="color: black;">append</span><span style="color: black;">&#40;</span>A<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; D.<span style="color: black;">append</span><span style="color: black;">&#40;</span>B<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #008000;">sum</span> +<span style="color: #66cc66;">=</span> val1<br />
&nbsp; &nbsp; &nbsp; i +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; C.<span style="color: black;">append</span><span style="color: black;">&#40;</span>A<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; D.<span style="color: black;">append</span><span style="color: black;">&#40;</span>B<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #008000;">sum</span> +<span style="color: #66cc66;">=</span> val2<br />
&nbsp; &nbsp; &nbsp; j -<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
<br />
&nbsp; j -<span style="color: #66cc66;">=</span> s - <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>C<span style="color: black;">&#41;</span> - <span style="color: #ff4500;">1</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>C<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&lt;</span> s:<br />
&nbsp; &nbsp; C.<span style="color: black;">append</span><span style="color: black;">&#40;</span>A<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; D.<span style="color: black;">append</span><span style="color: black;">&#40;</span>B<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">sum</span> +<span style="color: #66cc66;">=</span> A<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span> * B<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; i +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; j +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>C<span style="color: #66cc66;">,</span> D<span style="color: #66cc66;">,</span> <span style="color: #008000;">sum</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div></pre>
<p>算法的空间复杂度为 O(s)，即用来存储 C、D 的空间；时间复杂度为 O(n log n)。</p>
<p>============ 并不华丽的分割线&nbsp;============</p>
<p>最后说个题外的事情。这是最后一篇从以前“钟磬居”网站备份回来的算法文章了。当年的钟磬居有如昙花一现，好多文章都只存在于Google Reader的缓存中了。让我没想到的是，刚才搜一个东西的时候，搜索结果第一条竟然是这篇文章。当然不是你看到的这一篇，而是之前发在钟磬居中被转载出去的。一字不差啊，连我加的粗体都还在，也保留了我当时文章中的一个错误（这里已经修正）。当时的钟磬居跟现在的GoCalf一样，看的人不算太少，但没有人评论。想起中学时喜欢的一句话“纵是昙花一现，也有一个月下赏花人，应无所憾”。送给逝去的钟磬居，鼓励一下自己。继续努力。</p>
<p>再次强调，本文不是转载，是原文，是从已经关闭了的网站中恢复回来的原文。GoCalf网站中，如无特殊说明，一律原创。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/task-schedule-with-resource.html' rel='bookmark' title='任务调度问题：资源占用与释放'>任务调度问题：资源占用与释放</a></li>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
<li><a href='http://www.gocalf.com/blog/circularly-ordinal-array.html' rel='bookmark' title='在循环有序数组中查找指定元素'>在循环有序数组中查找指定元素</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection-2.html' rel='bookmark' title='单次遍历，带权随机选取问题（二）'>单次遍历，带权随机选取问题（二）</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/max-inner-product.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>求二叉树中两结点的最小公共祖先</title>
		<link>http://www.gocalf.com/blog/least-common-ancestor.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=least-common-ancestor</link>
		<comments>http://www.gocalf.com/blog/least-common-ancestor.html#comments</comments>
		<pubDate>Fri, 21 Oct 2011 14:34:35 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Least Common Ancestor]]></category>
		<category><![CDATA[二叉树]]></category>
		<category><![CDATA[微软面试]]></category>
		<category><![CDATA[数据结构]]></category>
		<category><![CDATA[最小公共父结点]]></category>
		<category><![CDATA[最小公共祖先]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[遍历二叉树]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1272</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/bin_tree.png" class="attachment-post-thumbnail wp-post-image" alt="bin_tree" title="bin_tree" /></div>据说这是微软的一道面试题，谁知道呢。

问题描述：找出二叉树上任意两个指定结点的最近共同父结点（LCA，Least Common Ancestor）。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/bin_tree.png" class="attachment-post-thumbnail wp-post-image" alt="bin_tree" title="bin_tree" /></div><p>据说这是微软的一道面试题，谁知道呢。</p>
<p>问题描述：找出二叉树上任意两个指定结点的最近共同父结点（LCA，Least Common Ancestor）。<span id="more-1272"></span></p>
<p>这算不上是一道算法题了，主要还是看数据结构基本知识和编程能力。</p>
<p>首先考虑最简单的情况——二叉树结点数据结构中有父指针。</p>
<p>这是不是非常简单呢？只要分别从两个结点出发向上走到树根，得到两个结点的分支路径，求出这两条路径相互重合部分的最靠下的结点，就是所求的LCA。这只需要 O(h) 的时空代价（设h是树高，n是树结点数目，平均情况下h = log(n)，最坏情况h = n）。</p>
<p>如果想再稍微节省一点儿时间和空间，可以先找出第一条分支路径，并用这些结点建立哈希表，然后从另外一个指定结点开始向上走到树根，每次遇到一个结点就到哈希表中查一下，一旦发现某个结点存在于哈希表中，这个结点就是所求的LCA。这个方法的代码示意如下：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> FindLCA<span style="color: black;">&#40;</span>node1<span style="color: #66cc66;">,</span> node2<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #808080; font-style: italic;"># Special cases.</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> node1 <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff7700;font-weight:bold;">not</span> node2:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> node1 <span style="color: #ff7700;font-weight:bold;">is</span> node2:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> node1<br />
<br />
&nbsp; <span style="color: #808080; font-style: italic;"># Get the first branch path.</span><br />
&nbsp; ancestors1 <span style="color: #66cc66;">=</span> <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> node1:<br />
&nbsp; &nbsp; ancestors1.<span style="color: black;">add</span><span style="color: black;">&#40;</span>node1<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; node1 <span style="color: #66cc66;">=</span> node1.<span style="color: black;">parent</span><br />
<br />
&nbsp; <span style="color: #808080; font-style: italic;"># Check if any ancestor of node2 is in the first branch path.</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> node2:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> node2 <span style="color: #ff7700;font-weight:bold;">in</span> ancestors1:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> node2 &nbsp; &nbsp;<span style="color: #808080; font-style: italic;"># Got it, the LCA.</span><br />
&nbsp; &nbsp; node2 <span style="color: #66cc66;">=</span> node2.<span style="color: black;">parent</span><br />
<br />
&nbsp; <span style="color: #808080; font-style: italic;"># These two nodes have no common ancestor.</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span></div></td></tr></tbody></table></div></pre>
<p>这样确实很简单，但实际情况是，通常二叉树结点中并没有父结点指针，这时候就要遍历二叉树找到这两个结点，并找出它们的LCA。</p>
<p>实际上，在遍历二叉树的时候，很容易就能够记录下根结点到任何结点的分支路径，只要有了分支路径，就可以对比找出LCA。</p>
<p>我们采取前序遍历，即N-L-R的顺序，使用堆栈来避免递归并且记录完整的分支路径。那么，在二叉树中查找指定结点的算法可以这样写：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> Dir:<br />
&nbsp; <span style="color: black;">&#40;</span>Undef<span style="color: #66cc66;">,</span> Left<span style="color: #66cc66;">,</span> Right<span style="color: black;">&#41;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> FindNodes<span style="color: black;">&#40;</span>root<span style="color: #66cc66;">,</span> nodeSet<span style="color: #66cc66;">,</span> findAll<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> root <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff7700;font-weight:bold;">not</span> nodeSet:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span><br />
<br />
&nbsp; pathDict <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><br />
&nbsp; path <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; curr <span style="color: #66cc66;">=</span> root<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> curr <span style="color: #ff7700;font-weight:bold;">or</span> path:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> curr: &nbsp; <span style="color: #808080; font-style: italic;"># Go down along left branch</span><br />
&nbsp; &nbsp; &nbsp; path.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>curr<span style="color: #66cc66;">,</span> Dir.<span style="color: black;">Left</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> curr <span style="color: #ff7700;font-weight:bold;">in</span> nodeSet:<br />
&nbsp; &nbsp; &nbsp; &nbsp; pathDict<span style="color: black;">&#91;</span>curr<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; nodeSet.<span style="color: black;">remove</span><span style="color: black;">&#40;</span>curr<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> nodeSet <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff7700;font-weight:bold;">not</span> findAll:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> pathDict<br />
&nbsp; &nbsp; &nbsp; curr <span style="color: #66cc66;">=</span> curr.<span style="color: black;">left</span><br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>curr<span style="color: #66cc66;">,</span> <span style="color: #008000;">dir</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">=</span> path.<span style="color: black;">pop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">dir</span> <span style="color: #66cc66;">==</span> Dir.<span style="color: black;">Right</span>: &nbsp; <span style="color: #808080; font-style: italic;"># Back from right branch</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> path: <span style="color: #ff7700;font-weight:bold;">return</span> pathDict<br />
&nbsp; &nbsp; &nbsp; <span style="color: black;">&#40;</span>curr<span style="color: #66cc66;">,</span> <span style="color: #008000;">dir</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">=</span> path.<span style="color: black;">pop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; path.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>curr<span style="color: #66cc66;">,</span> Dir.<span style="color: black;">Right</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> &nbsp;<span style="color: #808080; font-style: italic;"># Trun to right from left</span><br />
&nbsp; &nbsp; curr <span style="color: #66cc66;">=</span> curr.<span style="color: black;">right</span><br />
<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> pathDict</div></td></tr></tbody></table></div></pre>
<p>其中Dir这个类相当于是一个枚举，用来定义当前的分支方向。FindNodes除了需要二叉树根结点外，还需要一个待查找的结点集合。这个函数可以在二叉树中找到所有（或第一个）待查找结点的分支路径，并返回一个字典（结点 --&gt; 路径）。</p>
<p>可以看出，FindNodes函数按照前序顺序遍历整个二叉树，查找指定结点。每遇到一个结点，首先判断它是不是我们要找的，如果不是就沿着左边的分支下降到底，然后转入右侧分支。</p>
<p>有了FindNodes函数的支持，我们就可改写前面的FindLCA函数，即先遍历二叉树求出两个结点的分支路径，然后比较这两条路径找出LCA：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> FindLCA<span style="color: black;">&#40;</span>root<span style="color: #66cc66;">,</span> node1<span style="color: #66cc66;">,</span> node2<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #808080; font-style: italic;"># Special cases.</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> root <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff7700;font-weight:bold;">not</span> node1 <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff7700;font-weight:bold;">not</span> node2:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> node1 <span style="color: #ff7700;font-weight:bold;">is</span> node2:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> node1<br />
<br />
&nbsp; <span style="color: #808080; font-style: italic;"># Try to find the two nodes in the tree, and get their branch paths.</span><br />
&nbsp; nodeSet <span style="color: #66cc66;">=</span> <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>node1<span style="color: #66cc66;">,</span> node2<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; pathDict <span style="color: #66cc66;">=</span> FindNodes<span style="color: black;">&#40;</span>root<span style="color: #66cc66;">,</span> nodeSet<span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> nodeSet:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span><br />
<br />
&nbsp; path1 <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>i<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> pathDict<span style="color: black;">&#91;</span>node1<span style="color: black;">&#93;</span><span style="color: black;">&#93;</span><br />
&nbsp; path2 <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>i<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> pathDict<span style="color: black;">&#91;</span>node2<span style="color: black;">&#93;</span><span style="color: black;">&#93;</span><br />
<br />
&nbsp; <span style="color: #808080; font-style: italic;"># Compare the two paths, find out the LCA.</span><br />
&nbsp; lca <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><br />
&nbsp; minLen <span style="color: #66cc66;">=</span> <span style="color: #008000;">min</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>path1<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>path2<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>minLen<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> path1<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> path2<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">break</span><br />
&nbsp; &nbsp; lca <span style="color: #66cc66;">=</span> path1<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><br />
<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> lca</div></td></tr></tbody></table></div></pre>
<p>遍历二叉树查找所有指定的结点需要 O(n) 时间，O(h) 额外空间；对比两条分支路径需要 O(h) 的时间，因此总的时间代价为 O(n)，空间代价为 O(h)。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/circularly-ordinal-array.html' rel='bookmark' title='在循环有序数组中查找指定元素'>在循环有序数组中查找指定元素</a></li>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
<li><a href='http://www.gocalf.com/blog/traversing-binary-tree.html' rel='bookmark' title='程序基本功之遍历二叉树'>程序基本功之遍历二叉树</a></li>
<li><a href='http://www.gocalf.com/blog/calc-fibonacci.html' rel='bookmark' title='计算斐波纳契数，分析算法复杂度'>计算斐波纳契数，分析算法复杂度</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/least-common-ancestor.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>任务调度问题：资源占用与释放</title>
		<link>http://www.gocalf.com/blog/task-schedule-with-resource.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=task-schedule-with-resource</link>
		<comments>http://www.gocalf.com/blog/task-schedule-with-resource.html#comments</comments>
		<pubDate>Fri, 14 Oct 2011 16:10:19 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Google面试]]></category>
		<category><![CDATA[任务]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[调度]]></category>
		<category><![CDATA[贪心算法]]></category>
		<category><![CDATA[资源]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1263</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/task_with_resource.png" class="attachment-post-thumbnail wp-post-image" alt="task_with_resource" title="task_with_resource" /></div>问题描述：有n个任务，第i个任务运行时需要使用 R[i] 的资源，运行完毕后需要占用 O[i] 的资源（O[i] <= R[i]），假设现在我们总共有s的资源，要求设计一个调度算法，能保证所有任务能顺利执行；如果无法执行完，需要说明理由。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/task_with_resource.png" class="attachment-post-thumbnail wp-post-image" alt="task_with_resource" title="task_with_resource" /></div><p>据说这是2009年Google暑期实习招聘的笔试题。</p>
<p>问题描述：有n个任务，第i个任务运行时需要使用 R[i] 的资源，运行完毕后需要占用 O[i] 的资源（O[i] <= R[i]），假设现在我们总共有s的资源，要求设计一个调度算法，能保证所有任务能顺利执行；如果无法执行完，需要说明理由。<span id="more-1263"></span></p>
<p>举例：比如有n = 2个任务，R[1] = 10，O[1] = 2，R[2] = 5，O[2] = 3，总资源s = 10。如果先执行任务1，剩余资源10 - 2 = 8，可以执行任务2；反过来先执行任务2，剩余资源10 - 3 = 7，7 < r[1] = 10，无法执行任务1。</p>
<p>这道题的解法很简单，按照 R - O 从大到小排序就是可行的调度顺序，如果按照这个顺序无法执行完所有任务，那么其他任何顺序也都不行；反之，如果存在某个顺序使得所有任务能顺利执行，那么这个顺序一定也可以。</p>
<p>先看算法，稍后再做证明。</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> ScheduleTasks<span style="color: black;">&#40;</span>R<span style="color: #66cc66;">,</span> O<span style="color: #66cc66;">,</span> n<span style="color: #66cc66;">,</span> s<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #808080; font-style: italic;"># R: request</span><br />
&nbsp; <span style="color: #808080; font-style: italic;"># O: occupancy</span><br />
&nbsp; <span style="color: #808080; font-style: italic;"># R - O: temporal = request - occupancy</span><br />
&nbsp; tasks <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>i<span style="color: #66cc66;">,</span> R<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> O<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> R<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span> - O<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
&nbsp; tasks.<span style="color: black;">sort</span><span style="color: black;">&#40;</span>key<span style="color: #66cc66;">=</span><span style="color: #dc143c;">operator</span>.<span style="color: black;">itemgetter</span><span style="color: black;">&#40;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> reverse<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>taskId<span style="color: #66cc66;">,</span> req<span style="color: #66cc66;">,</span> occ<span style="color: #66cc66;">,</span> temp<span style="color: black;">&#41;</span> <span style="color: #66cc66;">=</span> tasks<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> req <span style="color: #66cc66;">&gt;</span> s <span style="color: #ff7700;font-weight:bold;">or</span> occ <span style="color: #66cc66;">&gt;</span> s:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #008000;">False</span><span style="color: #66cc66;">,</span> tasks<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; s -<span style="color: #66cc66;">=</span> occ<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #008000;">True</span><span style="color: #66cc66;">,</span> tasks<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div></pre>
<p>显然这是贪心法，那么贪心法是否一定能得到可行解呢？</p>
<p>假设存在一个可行解（任务的执行顺序）为：T1, T2, …, Tn。设其中存在两个相邻的任务 Ti 和 Ti+1，满足 R[i] - O[i] < R[i+1] - O[i+1]。</p>
<p>设执行任务j前的资源剩余量为s’，因为这是一个可行解，任务j和任务k都可以顺利执行，因此有：s’ - O[i] >= R[i+1]。</p>
<p>联列这两个式子可以得到：s’ >= R[i+1] + O[i] > R[i] + O[i+1]，即s’ - O[i+1] > R[i]，可见交换任务 Ti 和 Ti+1 的执行顺序后依旧是可行解。</p>
<p>以此类推，对于任何i（1 <= i < n），如果 R[i] - O[i] < R[i+1] - O[i+1]，我们都可以将这两个任务的顺序交换，最终得到的执行顺序是可行解。</p>
<p>综上所述，按照 R - O 从大到小排列所有的任务是可行解。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/max-inner-product.html' rel='bookmark' title='求内积最大的子数组'>求内积最大的子数组</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/task-schedule-with-resource.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>检测单向链表是否存在环</title>
		<link>http://www.gocalf.com/blog/circle-of-link-list.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=circle-of-link-list</link>
		<comments>http://www.gocalf.com/blog/circle-of-link-list.html#comments</comments>
		<pubDate>Fri, 14 Oct 2011 04:56:01 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[双指针]]></category>
		<category><![CDATA[环检测]]></category>
		<category><![CDATA[环长]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[链表]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1250</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/link_circle.png" class="attachment-post-thumbnail wp-post-image" alt="link_circle" title="link_circle" /></div>问题描述：在单向链表中，每个结点都包含一个指向下一个结点的指针，最后一个结点的这个指针被设置为空。但如果把最后一个结点的指针指向链表中存在的某个结点，就会形成一个环，在顺序遍历链表的时候，程序就会陷入死循环。我们的问题就是，如何检测一个链表中是否有环，如果检测到环，如何确定环的入口点（即求出环长，环前面的链长）。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/link_circle.png" class="attachment-post-thumbnail wp-post-image" alt="link_circle" title="link_circle" /></div><p>问题描述：在单向链表中，每个结点都包含一个指向下一个结点的指针，最后一个结点的这个指针被设置为空。但如果把最后一个结点的指针指向链表中存在的某个结点，就会形成一个环，在顺序遍历链表的时候，程序就会陷入死循环。我们的问题就是，如何检测一个链表中是否有环，如果检测到环，如何确定环的入口点（即求出环长，环前面的链长）。<span id="more-1250"></span></p>
<p>一种比较耗空间的做法是，从头开始遍历链表，把每次访问到的结点（或其地址）存入一个集合（hashset）或字典（dictionary），如果发现某个结点已经被访问过了，就表示这个链表存在环，并且这个结点就是环的入口点。这需要O(N)空间和O(N)时间，其中N是链表中结点的数目。</p>
<p>如果要求只是用O(1)空间、O(N)时间，应该怎么处理呢？</p>
<p>其实很简单，想象一下在跑道上跑步：两个速度不同的人在操场跑道上一圈一圈地跑，他们总会有相遇的时候。因此我们只需要准备两个指针，同时从链表头出发，一个每次往前走一步，另一个每次往前走两步。如果链表没有环，那么经过一段时间，第二个（速度较快的）指针就会到达终点；但如果链表中有环，两个指针就会在环里转圈，并会在某个时刻相遇。</p>
<p>大家也许会问，这两个指针要在环里转多少圈才能相遇呢？会不会转几千几万圈都无法相遇？实际上，第一个（速度慢的）指针在环里转满一圈之前，两个指针必然相遇。不妨设环长为L，第一个指针P1第一次进入环时，第二个指针P2在P1前方第a个结点处（0 < a < L），设经过x次移动后两个指针相遇，那么应该有0+x = a + 2x (mod L)，显然x = L-a。下面这张图可以清晰地表明这种关系，经过x = L-a次移动，P1向前移动了L-a个位置（相当于后退了a），到达P1′处，而P2向前移动了2L-2a个位置（相当于后退了2a），到达P2′处，显然P1′和P2′是同一点。</p>
<div id="attachment_1255" class="wp-caption alignnone" style="width: 510px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/two_pointers_in_ring.png" alt="two_pointers_in_ring" title="two_pointers_in_ring" width="500" height="425" class="size-full wp-image-1255 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">慢指针（P1）转一周之内，必然与快指针（P2）相遇</p></div>
<p>在知道链表内有环后，求环长是一件非常简单的事情，只要从刚才那个相遇点开始，固定P2，继续移动P1，直到P1与P2再次相遇，所经过的步数就是环长。</p>
<p>怎么求环前面那段子链的长度呢？很简单，让P1和P2都回到链表起点，然后让P2先往前走L次（每次往前走一步），然后P1和P2再同时往前走，当它们再次相遇时，P1所走的步数就是环前面的子链长度。</p>
<p>算法示意：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> CheckRing<span style="color: black;">&#40;</span>head<span style="color: black;">&#41;</span>:<br />
&nbsp; l1 <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span> &nbsp;<span style="color: #808080; font-style: italic;"># length of the chain before the ring</span><br />
&nbsp; l2 <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span> &nbsp;<span style="color: #808080; font-style: italic;"># length of the ring</span><br />
<br />
&nbsp; <span style="color: #808080; font-style: italic;"># Check if there is a ring.</span><br />
&nbsp; pos1 <span style="color: #66cc66;">=</span> head<br />
&nbsp; pos2 <span style="color: #66cc66;">=</span> head<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> pos2 <span style="color: #ff7700;font-weight:bold;">and</span> pos2.<span style="color: black;">next</span>:<br />
&nbsp; &nbsp; pos1 <span style="color: #66cc66;">=</span> pos1.<span style="color: black;">next</span><br />
&nbsp; &nbsp; pos2 <span style="color: #66cc66;">=</span> pos2.<span style="color: black;">next</span>.<span style="color: black;">next</span><br />
&nbsp; &nbsp; l1 +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">2</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> pos2 <span style="color: #ff7700;font-weight:bold;">and</span> pos1 <span style="color: #66cc66;">==</span> pos2:<br />
&nbsp; &nbsp; &nbsp; l2 <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">break</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> l2:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> pos2: l1 +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>l1<span style="color: #66cc66;">,</span> l2<span style="color: black;">&#41;</span> &nbsp;<span style="color: #808080; font-style: italic;"># l2 should be 0</span><br />
<br />
&nbsp; <span style="color: #808080; font-style: italic;"># Calc the length of the ring.</span><br />
&nbsp; pos1 <span style="color: #66cc66;">=</span> pos2.<span style="color: black;">next</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> pos1 <span style="color: #66cc66;">!=</span> pos2:<br />
&nbsp; &nbsp; pos1 <span style="color: #66cc66;">=</span> pos1.<span style="color: black;">next</span><br />
&nbsp; &nbsp; l2 +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
<br />
&nbsp; <span style="color: #808080; font-style: italic;"># Calc the length of the chain before the ring.</span><br />
&nbsp; l1 <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span><br />
&nbsp; pos1 <span style="color: #66cc66;">=</span> head<br />
&nbsp; pos2 <span style="color: #66cc66;">=</span> head<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>l2<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; pos2 <span style="color: #66cc66;">=</span> pos2.<span style="color: black;">next</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> pos1 <span style="color: #66cc66;">!=</span> pos2:<br />
&nbsp; &nbsp; pos1 <span style="color: #66cc66;">=</span> pos1.<span style="color: black;">next</span><br />
&nbsp; &nbsp; pos2 <span style="color: #66cc66;">=</span> pos2.<span style="color: black;">next</span><br />
&nbsp; &nbsp; l1 +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>l1<span style="color: #66cc66;">,</span> l2<span style="color: black;">&#41;</span></div></td></tr></tbody></table></div></pre>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/circularly-ordinal-array.html' rel='bookmark' title='在循环有序数组中查找指定元素'>在循环有序数组中查找指定元素</a></li>
<li><a href='http://www.gocalf.com/blog/unbalcanced-coin.html' rel='bookmark' title='利用不均匀硬币产生等概率'>利用不均匀硬币产生等概率</a></li>
<li><a href='http://www.gocalf.com/blog/calc-fibonacci.html' rel='bookmark' title='计算斐波纳契数，分析算法复杂度'>计算斐波纳契数，分析算法复杂度</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
<li><a href='http://www.gocalf.com/blog/least-common-ancestor.html' rel='bookmark' title='求二叉树中两结点的最小公共祖先'>求二叉树中两结点的最小公共祖先</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/circle-of-link-list.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>《塞尔达传说：黎明公主》攻略：第二章 死亡山颠的咆哮</title>
		<link>http://www.gocalf.com/blog/zelda-tp-ch2.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=zelda-tp-ch2</link>
		<comments>http://www.gocalf.com/blog/zelda-tp-ch2.html#comments</comments>
		<pubDate>Wed, 12 Oct 2011 00:45:40 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[游戏]]></category>
		<category><![CDATA[Game]]></category>
		<category><![CDATA[Twilight Princess]]></category>
		<category><![CDATA[Wii]]></category>
		<category><![CDATA[任天堂]]></category>
		<category><![CDATA[塞尔达传说]]></category>
		<category><![CDATA[游戏攻略]]></category>
		<category><![CDATA[黎明公主]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1211</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_logo.png" class="attachment-post-thumbnail wp-post-image" alt="tp_ch02_logo" title="tp_ch02_logo" /></div>第二章 死亡山巅的咆哮（大地的子民）

打倒达巴巴之后，林克得到一个完整的心之容器（加一格血）。

米德娜出现并将林克传送回法隆之泉处，顺路来到柯洛处，可以补充一点灯油，之前关上的栅栏打开了，过去后就来到海拉尔平原（Hyrule Field）。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_logo.png" class="attachment-post-thumbnail wp-post-image" alt="tp_ch02_logo" title="tp_ch02_logo" /></div><h3>第二章 死亡山巅的咆哮（大地的子民）</h3>
<p>打倒达巴巴之后，林克得到一个完整的心之容器（加一格血）。</p>
<p>米德娜出现并将林克传送回法隆之泉处，顺路来到柯洛处，可以补充一点灯油，之前关上的栅栏打开了，过去后就来到海拉尔平原（Hyrule Field）。<span id="more-1211"></span></p>
<h4>海拉尔平原</h4>
<h5>森林复苏</h5>
<p>顺路一直往平原的北面走，途中会遇到一位滑稽的邮递员，他告诉林克，他奔波于世界各地为大家送邮件，无论以后林克在哪里，他都会及时把邮件送到。从北面的小径离开海拉尔平原后，林克来到第二堵黑暗之墙的面前，米德娜带着林克进入了黑暗世界，林克又变成了狼的形态。顺着路没走多远便发现了塔洛掉下的剑，林克嗅了嗅，可以通过感知追踪孩子们留下的气味，跟随气味一直来到一断桥处，这里又遇见了暗影使者，打倒后，天空出现了黑暗空洞，米德娜告诉林克，她可以发动魔法让林克在两个黑暗空洞之间来回传送。前方没路了，林克只好让米德娜开启传送门回到森之神殿之前的那片地区，还记得当时看到的遗留在路旁的桥体吗?在桥体处，米德娜发动魔法，将桥体移到之前的断桥处修通道路，过桥之后顺着路走可以进入卡卡里科村（Kakariko Village）。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_01.jpg"><div id="attachment_1227" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_01-700x466.jpg" alt="tp_ch02_01" title="tp_ch02_01" width="700" height="466" class="size-large wp-image-1227 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">林克来到海拉尔平原（Hyrule Field）</p></div></a></p>
<h4>卡卡里科村</h4>
<h5>被黑暗覆盖的小镇</h5>
<p>刚刚到村口又遇到了暗影使者，比较有难度的是其中一个始终与另两个保持一定距离，林克只好先把远处的一个杀掉再迅速把其余两个同时干掉。此时泉水处出现了第三位光之精灵，但是由于黑暗力量的笼罩，它还无法现出真身，它交给林克第二个光之容器，让林克收集散落在卡卡里科村的光之泪。进入卡卡里科村后，发现这里面基本每个房子里都有携带光之泪的虫子。不过林克还是很担心孩子们，他顺着气温来到村子门口的一座建筑前，但是林克在狼形态下是无法开门的，他围着房子转了转，米德娜告诉林克可以借助树枝跳到屋顶，这个主意不错，来到屋顶后，林克从中间的洞跳了下去。孩子们都在这里，林克一下安心了，不过这里还有一些林克不认识的人，林克通过感知听到了他们的谈话，原来都是村里的居民，他们都很害怕，不过柯林坚信林克一定会回来救他们，米德娜嘲笑林克，林克要保护的人就在眼前，但是现在的林克却无能为力，没办法，林克只好暂时离开。林克捡起地上的木棍，到火台上点燃后，把房内的蜡烛全部引燃（可以发现三只虫子），房子中间的雕像移开，出现了一条地道，林克顺着地道出了房间。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_02.jpg"><div id="attachment_1229" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_02-700x466.jpg" alt="tp_ch02_02" title="tp_ch02_02" width="700" height="466" class="size-large wp-image-1229 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">卡卡里科村（Kakariko Village）被黑暗覆盖，需要收集光之泪</p></div></a></p>
<p>通过地道林克来到了卡卡里科墓地（Graveyard），发现这里有携带着光之泪的虫子，杀掉后，林克回到村子里，来到商店（General Store）的房子右边，林克发现大楼的底部有个小洞，钻进去找到虫子，干掉它收集到光之泪，再原路出来。林克来到商店南边，走上坡道，这里是艾尔德旅馆（Elde Inn）。跃进旅馆的阳台，跳到下面的地板上，虫子藏在壁炉里不出来，聪明的林克从壁炉里取出一支木棒，再跳到桌子附近的火炬那里点燃，然后引燃壁炉，把烟囱里的虫子给驱赶出来，另一支虫子要进入旅馆大厅，走上楼梯，在客房里找到。出来后林克来到住宅区（Residential House），在街的西面，这个房子里有另一只虫，穿过南边的2间房子，发现有个可以跳上的坡道，然后跳过一个个房顶，直到有虫子的那间房子的屋顶，林克发现这里房顶有个裂缝，可以从这下到房子内。林克把木箱子推向墙壁后，虫子从下面窜了出来，杀了它得到光之泪后，米德娜会带着林克跳出去。林克来到巴恩斯的炸弹商店（Barnes Bomb shop），在这个大型建筑物的北面，找到一些可以攀爬的箱子，然后爬上屋顶。然后可以看到炸弹商店的一扇窗户，林克勇猛地撞碎玻璃跳了进去，直接来到楼上然后撞击书架，就会有虫子飞出来，得到光之泪后爬上棚架，林克发现了出口。从炸弹商店的窗口爬出来，林克发现自己已经上到了西北山丘（The Northwestern Hills），顺着路向上，林克来到一个标着"Danger!"的建筑物面前。进到房子里面，林克发现这里到处都是火药，虫子也藏在角落里，林克没有办法，只好在地上捡起一根木棍，引燃木棍后，用它来把壁炉点着，火星蹦了出来，火药被点燃了，林克见状赶紧原路跑开。刚一出房子，只听身后一声巨响，连屋带虫一起化为了灰烬，林克也得到了三颗光之泪。林克顺着斜坡上到了山顶，这里的房里可以找到一条虫子，村里已经没有虫子了，但是光之泪还没有收集全，看来有虫子飞到了更远的地方去了。林克只好从村子北面的一个大山洞出村，一路来到死亡山（Death Mountain）的脚下。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_03.jpg"><div id="attachment_1230" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_03-700x466.jpg" alt="tp_ch02_03" title="tp_ch02_03" width="700" height="466" class="size-large wp-image-1230 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">在屋顶上看到炸弹商店的一扇窗户，可以撞碎玻璃跳进去</p></div></a></p>
<h4>死亡山</h4>
<p>在米德娜的帮助下跳上了一个峭壁，林克顺着路往山上走，一路上还要躲过一连串的热泉。林克在这片区域中找到了三只虫子，解决掉后继续前进，不远处有一个嚎叫之岩（Howling Shrine），林克隐约听到嚎叫之岩会发出狼的嚎声，狼形态下的林克跟着听到的声音也嚎叫了起来，原来是林克的嚎声引起了远方金狼的共鸣，难道就是上次教林克绝技的那只狼？带着疑问，林克继续前进，再次遇到了黑暗使者，这次数量增加到了四个，但是林克还是轻松取胜，之后便开启了死亡山的黑暗空洞。光之泪还没收集齐，林克只好继续前进，米德娜带着林克不断向上跳，来到一个盆地处，跳下去解决掉虫子，最后一颗光之泪终于到手了，卡卡里科村净化完成，村子又重新回到了光明的怀抱。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_04.jpg"><div id="attachment_1231" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_04-700x466.jpg" alt="tp_ch02_04" title="tp_ch02_04" width="700" height="466" class="size-large wp-image-1231 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">死亡山</p></div></a></p>
<h5>大地之民族</h5>
<p>林克回到村口的泉水处，第三位光之精灵艾尔丁（Eldin）也恢复了其真实的形态，艾尔丁告诉林克，死亡山上的戈隆一族有着能够帮助林克的宝物，看来林克只有上山去拜访戈隆一族了。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_05.jpg"><div id="attachment_1232" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_05-700x466.jpg" alt="tp_ch02_05" title="tp_ch02_05" width="700" height="466" class="size-large wp-image-1232 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">恢复了真实的形态的第三位光之精灵艾尔丁（Eldin）</p></div></a></p>
<p>村里的村民和小孩们都被解救出来了，柯林非常高兴，他就知道林克会来救大家，可是马洛和塔洛还是很不服气，怪林克那么晚才来，这时当初在房子看到的陌生人上前来自我介绍，原来他叫雷那多（Renado），是村里的牧师，另外一位就是炸弹店的老板巴恩斯，雷那多告诉林克，孩子们在这里很安全，让林克放心去找伊莉娅。林克也很担心伊莉娅，于是继续上路，林克再次前往死亡山，刚爬上峭壁，却发现有个戈隆人挡路，两句话不对戈隆人毫不客气地将林克撞了下来，看来暂时是没法上去了，只得离开。回到村里，雷那多告诉林克，奥东村的村长布有办法对付挡路的戈隆人。那不是林克的家乡么，很久没回去了，林克也挺想念大家的，于是打算回奥东村一趟，顺便找村长布想办法帮忙。林克正在犯愁，离家乡那么远，怎么回去呢？正在这时艾普娜出现，可能是很久没见了，艾普娜有点兴奋，林克跳到艾普娜背上试图让她安静下来，骑上之后，按屏幕下方出现的提示做就可以了，一开始是利用左手手柄左右晃动，最后一下则是按A（看见“SEIZE”提示时），将马驯服，艾普娜又变得跟往常一样温和了。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_06.jpg"><div id="attachment_1233" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_06-700x466.jpg" alt="tp_ch02_06" title="tp_ch02_06" width="700" height="466" class="size-large wp-image-1233 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">艾普娜过于兴奋，林克跳到她背上试图让她安静下来</p></div></a></p>
<h4>奥东村</h4>
<h5>相扑！！</h5>
<p>林克骑着艾普娜飞奔，很快便回到了法隆森林，经过奥东之泉时，林克想起了在死亡山上遇到金狼的事情，来到奥东之泉看到了金狼蹲在那里，林克走上前，金狼又是二话没说扑了上来，一阵眩晕后，不死勇士再次出现，看来林克又可以学到新的技能了。学会新的技能后，林克回到奥东村，径直来到村长布的家，林克向村长表明了来意，布将林克带到了里屋，他准备给林克传授摔跤的技能，聪明的林克没一会儿就学会了（第一局很容易，只要闪避后按住A攻击就可以了；第二局则要闪避后，挥动右手手柄击打对手，然后再按A攻击），学会了摔跤，就不怕戈隆人了，当林克正准备离去，村长又将自己的宝物钢之靴（Iron Boots）交给了林克，这对林克将来的冒险大有帮助。告别村长，林克打算去拜访老朋友农场主，农场主看到林克回来了也很高兴，他有件神秘的礼物准备送给林克，但条件是要林克打破他的赶羊纪录，这对林克来说再简单不过了，打破他的纪录后林克得到了一块<a href="http://www.gocalf.com/blog/zelda-tp-heartpiece.html#H05">心之碎片</a>。随后告别农场主，该是继续冒险的时候了。</p>
<h5>勇敢的少年</h5>
<p>林克回到卡卡里科村，刚进村子就看见兽人来袭，带头的兽人首领凶残地撞向贝思，柯林挺身而出推开了贝思，自己却被兽人首领撞到并抓走了。愤怒的林克快马加鞭地追赶了上去，第一场强制马上战！一路追到海拉尔平原上，兽人头领会不断招呼喽啰来阻拦林克，不过都被林克轻松搞定（如果怕麻烦又臂力超群的话，可以挥剑来斩射来的箭，然后完全无视小怪），林克在重创兽人首领后，其带着柯林向艾尔丁大桥逃去，林克追了上去，这时又出现了兽人弓箭手，用火箭点燃了早已准备好的草堆封住了桥头两边的去路，一场生死决斗在所难免，单挑战中，接近头目时注意快速回避，同时狂挥右手的手柄，成功的话一击就可以KO。兽人首领也不是林克的对手，最后林克挥剑将兽人首领击落桥下，林克带着受伤的柯林回到卡卡里科村，林克看着柯林非常难过，柯林告诉林克，他已经将林克作为自己的目标，将来也要像林克一样勇敢强壮，柯林的话给了林克很大的鼓舞，林克振作起来，再次来到死亡山脚下。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_07.jpg"><div id="attachment_1234" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_07-700x466.jpg" alt="tp_ch02_07" title="tp_ch02_07" width="700" height="466" class="size-large wp-image-1234 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">与兽人首领之间的一场马上战斗</p></div></a></p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_08.jpg"><div id="attachment_1235" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_08-700x466.jpg" alt="tp_ch02_08" title="tp_ch02_08" width="700" height="466" class="size-large wp-image-1235 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">在艾尔丁大桥上与兽人首领生死决斗</p></div></a></p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_09.jpg"><div id="attachment_1236" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_09-700x466.jpg" alt="tp_ch02_09" title="tp_ch02_09" width="700" height="466" class="size-large wp-image-1236 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">骑马战胜兽人的林克，英姿飒爽</p></div></a></p>
<h5>上山</h5>
<p>准备上山，上山前记得到村子新开的杂货店（入口第一间）买个铁盾牌，后面迷宫里会有很多敌人会火系攻击，现在的木盾很容易会被火烧掉。上山后林克穿上了重力靴，加上布所教授的摔跤技巧，挡路的戈隆人就拿林克没办法了。一路前进，途中还会遇到一些好斗的戈隆人，但是也有好心的戈隆人会帮林克跳上峭壁，峭壁喷出上的蒸汽，只要林克穿上钢之靴就能顺利通过。一直来到山顶的洞穴中，这里会遇到戈隆族的领袖，林克表明了来意，但是显然林克想要的宝物没在这里，但是戈隆族长告诉林克，戈隆矿山（Goron Mines）是他们世代守护的地方，现在被黑暗势力所侵吞了，而且他们有位伙伴被黑暗势力魔化了并关在矿山最深处，希望林克能帮助他们救出同伴，驱赶黑暗势力。林克爽快答应下，但是族长还是不太放心，要考验一下林克的实力，戈隆族长果然很强，一下就将林克推下擂台，林克只好穿上钢之靴后再上去挑战，战胜戈隆族长后，他终于放心的让林克进入了戈隆矿山。</p>
<h4>戈隆矿山迷宫</h4>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_10.jpg"><div id="attachment_1237" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_10-700x611.jpg" alt="tp_ch02_10" title="tp_ch02_10" width="700" height="611" class="size-large wp-image-1237 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">戈隆矿山迷宫地图</p></div></a></p>
<p><strong>房间1：</strong>林克进入戈隆矿山，这里到处都是炙热的岩浆，利用钢之靴可以关闭喷火的机关，不过有时间限制，必须快速通过。北面的门要先从右边的路上到第二层，用同样的方法按下按钮关闭第二个喷火机关后快速通过，之后再用钢之靴站到门旁边的开关上打开门进入房间2。</p>
<p><strong>房间2：</strong>这里先用钢之靴压下开关可以启动磁力机，穿着钢之靴站在其磁力范围内的话会被吸上去，利用它到房间西南角能够得到一把小钥匙，之后用它打开东边的门前往房间3。</p>
<p><strong>房间3：</strong>这里的火蜥蜴只有攻击它们的尾巴时才能对其造成伤害，当它们向你吐火的时候，绕着它们跑，抓住时机使用旋转剑法。去房间3的西北角，然后从外面绕过去后可以见到链子开关，穿上钢之靴能够将之拉出来，然后迅速绕回来在墙关闭之前朝东面进入房间4。</p>
<p><strong>房间4：</strong>来到房间4，这个房间要先用钢之靴沉入水底，然后穿过水低铁丝网上的洞，到最北面的按钮可以激活磁场，这样钢之靴就可以吸附在天花板上行动，不过只能在有磁矿的墙面上行走，继续前进来到5号房间。</p>
<p><strong>房间5：</strong>这里能见到一位戈隆长老，他将大钥匙的一部分交到林克手上，并告诉林克，想要打开关押他们同伴的大门还必须找到剩下的两部分钥匙。林克接过钥匙后从长老后面的楼梯上到二层，途中可以遇到戈隆矿山的欧库。利用钢之靴通过有水的房间后回到房间3，在西北角有个心之碎片，然后回到东南边找到门，跳下去回到房间2。这时林克来到房间2的上部，可以开启另一个磁力机，于是便能向北边前进进入房间6。</p>
<p><strong>房间6：</strong>把里面的敌人都解决掉，西北角的水里能够找到一把小钥匙，之后过去找到开关，可以激活磁场上到天花板上，沿着天花板走到高台上然后跳下来，启动另一个机关之后脱掉钢之靴跳下，在进入磁力范围时再穿上钢之靴就能被磁力吸到对面的墙壁上，之后走到平台上击打状态转换水晶，可以打开大门，林克迅速进入，再次穿上钢之靴走到高台上，林克在右边的高台找到一个心之碎片，来到左边砍断绳索放下大门，就是去房间7的路。</p>
<p><strong>房间7：</strong>跳下进入房间7，这里正东面有把小钥匙，有了它林克就能打开通往西面的门了前往房间8了。</p>
<p><strong>房间8：</strong>来到房间8，在右边的平台上有一把小钥匙，拿到之后可以前往房间9。</p>
<p><strong>房间9：</strong>到房间9找到第二位长老，他会给林克大钥匙的第二部分，之后从长老后面的楼梯上去回到房间8的上层，然后前往房间10。</p>
<p><strong>房间10：</strong>在房间10里，林克遇到小BOSS，一个狂暴的戈隆勇士，穿上钢之靴与其战斗，把他打在地上缩作一团时，可以冲上前将其丢下岩浆，不过他还不肯轻易罢休，看来还得费点力气，战胜后，林克进入南面的小房间内，这里的箱子内可以拿到英雄之弓（Hero’s Bow），看来这就是牧师雷那多告诉林克的戈隆族的宝物，林克用它射断面前平台上的绳索，于是就能进入到南面的房间11了。</p>
<p><strong>房间11：</strong>房间11里有很多石像，正当林克上前查看时，石像被激活了，用箭射它们上部的红水晶能让其停止攻击，之后就可以将它们往外拉。林克在房间的东面能够得到指南针，继续前进走西面的房间来到房间12。</p>
<p><strong>房间12：</strong>林克见到了最后一位长老，并得到最后一部分的大钥匙，得到大钥匙后，就可以去矿山深处解救狂暴的戈隆族同伴了。</p>
<p><strong>房间13：</strong>林克前进来到房间13，这里的天花板上有许多火焰虫，用弓箭将它们射掉，来到门前，利用旁边的开关，上到天花板上，林克会发现在门的上面有一个状态水晶，掏出弓箭射击水晶即可打开门。</p>
<p><strong>房间7：</strong>一路回到房间7，到之前有个活动石像的地方，就在房间最东面。用弓箭干掉它并将其拉出来，通过背后的路来到房间7的高处，打开磁力机，林克穿上钢之靴吸附到磁力机上，用弓箭射断东北方的桥索来到房间14，消灭所有的怪后，林克站到了关押狂暴的戈隆族人的门前。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_11.jpg"><div id="attachment_1238" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_11-700x560.jpg" alt="tp_ch02_11" title="tp_ch02_11" width="700" height="560" class="size-large wp-image-1238 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">戈隆矿山迷宫房间7</p></div></a></p>
<p><strong>BOSS战：</strong>福里乌斯（Twilit Iginiter——Fryus）</p>
<p>进门后看到福里乌斯，林克先用弓箭射其头顶发光的宝石，射中后他会痛苦得到处乱撞，林克迅速上前抓住他的脚链并换上钢之靴向后拖，福里乌斯会绊倒在地上，这时迅速上前挥砍其头顶的宝石，几个回合后，福里乌斯头顶的宝石破碎了，控制他的黑暗力量消失了，之后米德娜出现，带着林克回到了戈隆矿山的外面。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_12.jpg"><div id="attachment_1240" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_12-700x560.jpg" alt="tp_ch02_12" title="tp_ch02_12" width="700" height="560" class="size-large wp-image-1240 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">BOSS：福里乌斯（Twilit Iginiter——Fryus）</p></div></a></p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_13.jpg"><div id="attachment_1242" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/tp_ch02_13-700x560.jpg" alt="tp_ch02_13" title="tp_ch02_13" width="700" height="560" class="size-large wp-image-1242 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">福里乌斯头顶的宝石破碎，控制他的黑暗力量消失，他恢复正常</p></div></a></p>
<hr />
<p>参考：</p>
<ul style="padding-right: 40px; ">
<li><a href="http://wii.tgbus.com/glmj/gl/200611/20061129114849.shtml" target="_blank">《塞尔达传说：黄昏公主》图文全攻略</a>&nbsp;by WiiBbs 攻研部 Szh、三代鬼彻、天堂的翅膀</li>
<li><a href="http://www.cngba.com/thread-16520313-1-1.html" target="_blank">《塞尔达传说 黄昏公主》完美攻略研究</a> by www.cngba.com 鸡蛋</li>
<li><a href="http://tv.duowan.com/0710/57154029137.html" target="_blank">Wii《塞尔达传说：黎明公主》流程攻略</a></li>
</ul>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/zelda-tp-intro.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：剧情介绍'>《塞尔达传说：黎明公主》攻略：剧情介绍</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-characters.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：角色介绍'>《塞尔达传说：黎明公主》攻略：角色介绍</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch3.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：第三章 深海鱼族的传说'>《塞尔达传说：黎明公主》攻略：第三章 深海鱼族的传说</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch1.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：初章 英雄传说的扉页'>《塞尔达传说：黎明公主》攻略：初章 英雄传说的扉页</a></li>
<li><a href='http://www.gocalf.com/blog/check-udisk.html' rel='bookmark' title='U盘检测软件：ChipGenius，MyDiskTest'>U盘检测软件：ChipGenius，MyDiskTest</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/zelda-tp-ch2.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[《塞尔达传说：黎明公主》攻略]]></series:name>
	</item>
		<item>
		<title>利用不均匀硬币产生等概率</title>
		<link>http://www.gocalf.com/blog/unbalcanced-coin.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=unbalcanced-coin</link>
		<comments>http://www.gocalf.com/blog/unbalcanced-coin.html#comments</comments>
		<pubDate>Sat, 08 Oct 2011 14:49:24 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[不均匀硬币]]></category>
		<category><![CDATA[抛硬币]]></category>
		<category><![CDATA[概率]]></category>
		<category><![CDATA[等概率]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[随机数]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1199</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/unbalanced_coin.png" class="attachment-post-thumbnail wp-post-image" alt="unbalanced_coin" title="unbalanced_coin" /></div>问题描述：有一枚不均匀的硬币，已知抛出此硬币后，正面向上的概率为p（0 < p < 1）。请利用这枚硬币产生出概率相等的两个事件。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/unbalanced_coin.png" class="attachment-post-thumbnail wp-post-image" alt="unbalanced_coin" title="unbalanced_coin" /></div><p>问题描述：有一枚不均匀的硬币，已知抛出此硬币后，正面向上的概率为p（<code class="codecolorer text geshi"><span class="text">0 &lt; p &lt; 1</span></code>）。请利用这枚硬币产生出概率相等的两个事件。</p>
<p>这个问题跟之前的<a href="http://www.gocalf.com/blog/build-rank3-from-rand5.html">利用等概率Rand5产生等概率Rand3</a>非常像，但却简单的多。几个月前还为这个事情头疼了一下，现在想来真是不应该。<span id="more-1199"></span></p>
<p>某一次抛出硬币，正面向上的概率是p，反面向上的概率是1 - p，当p不等于0.5时，这两个事件的概率就不一样了。怎么能凑出等概率呢？还是要利用概率的加法和乘法法则。这里用乘法，也就是连续的独立事件。</p>
<p>连续抛两次硬币，正反面的出现有四种情况，概率依次为：</p>
<ol>
<li>两次均为正面：p * p</li>
<li>第一次正面，第二次反面：p * (1 - p)</li>
<li>第一次反面，第二次正面：(1 - p) * p</li>
<li>两次均为反面：(1 - p) * (1 - p)</li>
</ol>
<p>这不，中间两种情况的概率是完全一样的。于是问题的解法就是连续抛两次硬币，如果两次得到的相同则重新抛两次；否则根据第一次（或第二次）的正面反面情况，就可以得到两个概率相等的事件。</p>
<p>用Python程序模拟一下这个过程，首先是一个叫做UnbalancedCoin的类，用来模拟这枚不均匀的硬币。Flip方法表示抛一次硬币，返回值True代表正面，False代表反面。根据要求，这个函数返回True和False的概率分别是p和1 - p。函数MakeEqualProb利用参数coin（这枚不均匀硬币）构造出两个事件（依旧用True和False表示），并且这两个事件的概率都是0.5。</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">random</span> <span style="color: #ff7700;font-weight:bold;">import</span> Random<br />
<br />
<span style="color: #ff7700;font-weight:bold;">class</span> UnbalancedCoin:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> p<span style="color: #66cc66;">,</span> rand<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> <span style="color: #ff4500;">0.0</span> <span style="color: #66cc66;">&lt;</span> p <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">1.0</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'invalid p'</span><br />
&nbsp; &nbsp; <span style="color: #008000;">self</span>._p <span style="color: #66cc66;">=</span> p<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> rand <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; &nbsp; rand <span style="color: #66cc66;">=</span> Random<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">self</span>._rand <span style="color: #66cc66;">=</span> rand<br />
<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> Flip<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._rand.<span style="color: #dc143c;">random</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&lt;</span> <span style="color: #008000;">self</span>._p<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> MakeEqualProb<span style="color: black;">&#40;</span>coin<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:<br />
&nbsp; &nbsp; a <span style="color: #66cc66;">=</span> coin.<span style="color: black;">Flip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> a <span style="color: #66cc66;">!=</span> coin.<span style="color: black;">Flip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> a</div></td></tr></tbody></table></div></pre>
<p>对于不同的p值，模拟实验十万次，得到如下的（结果为True的）概率分布，其中蓝线是不均匀硬币抛出后正面向上的概率，红线是构造出来的两个事件之一（第一次正面向上，第二次反面向上）的概率。</p>
<div id="attachment_1203" class="wp-caption alignnone" style="width: 516px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/10/make_equal_prob.png" alt="make_equal_prob" title="make_equal_prob" width="506" height="530" class="size-full wp-image-1203 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">Python程序模拟实验得到的不均匀硬币产生的概率与自定义事件的概率</p></div>
<p>如果问题改变一下，把“一枚”改成“一种”，那解决办法就更简单有趣了，把两枚同样的不均匀硬币正面相对粘在一起，就可以得到一个均匀的组合币，抛出这枚组合币就可以得到等概率的两个事件。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/random-selection.html' rel='bookmark' title='单次遍历，等概率随机选取问题'>单次遍历，等概率随机选取问题</a></li>
<li><a href='http://www.gocalf.com/blog/shuffle-algo.html' rel='bookmark' title='等概率随机排列数组（洗牌算法）'>等概率随机排列数组（洗牌算法）</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection-2.html' rel='bookmark' title='单次遍历，带权随机选取问题（二）'>单次遍历，带权随机选取问题（二）</a></li>
<li><a href='http://www.gocalf.com/blog/the-probability-of-two-boys.html' rel='bookmark' title='条件概率：两个都是男孩的概率'>条件概率：两个都是男孩的概率</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/unbalcanced-coin.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>水木社区、小百合、饮水思源、日月光华全站十大同步博客</title>
		<link>http://www.gocalf.com/blog/bbs-top-10.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=bbs-top-10</link>
		<comments>http://www.gocalf.com/blog/bbs-top-10.html#comments</comments>
		<pubDate>Thu, 29 Sep 2011 15:21:58 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[互联网]]></category>
		<category><![CDATA[RSS订阅]]></category>
		<category><![CDATA[十大博客]]></category>
		<category><![CDATA[小百合]]></category>
		<category><![CDATA[水木十大]]></category>
		<category><![CDATA[水木社区]]></category>
		<category><![CDATA[百合十大]]></category>
		<category><![CDATA[饮水思源]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1183</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/top10.png" class="attachment-post-thumbnail wp-post-image" alt="top10" title="top10" /></div>gdh同学利用Google Blogspot和Google Picasa制作了四个博客，分别收集了清华水木社区、南大小百合、上海交通大学饮水思源和复旦大学日月光华的全站十大，不但保留了文章全文，还存储了图片，几乎是与这几个BBS同步更新的，非常方便。欢迎参观，猛烈点击小广告。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/top10.png" class="attachment-post-thumbnail wp-post-image" alt="top10" title="top10" /></div><p>如果你喜欢订阅几大校园BBS全站十大，强烈推荐<a href="http://www.truevue.org/" target="_blank">gdh</a>做的十大博客（需翻墙）：</p>
<ul>
<li>水木十大：<a href="http://smthot.blogspot.com/" target="_blank">http://smthot.blogspot.com/</a></li>
<li>小百合十大：<a href="http://lilytop.blogspot.com/" target="_blank">http://lilytop.blogspot.com/</a></li>
<li>饮水思源十大：<a href="http://sjtutop.blogspot.com/" target="_blank">http://sjtutop.blogspot.com/</a></li>
<li>日月光华十大：<a href="http://fudantop.blogspot.com/" target="_blank">http://fudantop.blogspot.com/</a></li>
</ul>
<div><span id="more-1183"></span></div>
<p>之前就一直用<a href="https://www.google.com/reader" target="_blank">Google Reader</a>订阅着水木的十大，不过非常郁闷的是水木RSS中的文章不完整，稍微长点儿文章就被截断了，再有就是图片附件都看不到，要点开进入到水木才能看得到。但经常有很不错的文章，却因为种种原因被删除或者合集了，再想看到原文原图就很困难了，带来了不少遗憾。</p>
<p><a href="http://www.truevue.org/" target="_blank">gdh</a>同学利用Google Blogspot和Google Picasa制作了四个博客，分别收集了清华水木社区、南大小百合、上海交通大学饮水思源和复旦大学日月光华的全站十大，不但保留了文章全文，还存储了图片，几乎是与这几个个BBS同步更新的，非常方便。欢迎大家前往以上博客参观，猛烈点击小广告，也可以直接把上述地址扔到Google Reader中进行订阅。</p>
<p>原文地址：<a href="http://www.truevue.org/web/smth-top-10-smthot" target="_blank">水木十大博客</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/bbs-top-10.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>单次遍历，带权随机选取问题（二）</title>
		<link>http://www.gocalf.com/blog/weighted-random-selection-2.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=weighted-random-selection-2</link>
		<comments>http://www.gocalf.com/blog/weighted-random-selection-2.html#comments</comments>
		<pubDate>Mon, 26 Sep 2011 03:27:16 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Heap]]></category>
		<category><![CDATA[Weighted Random Sample]]></category>
		<category><![CDATA[单次遍历]]></category>
		<category><![CDATA[带权概率]]></category>
		<category><![CDATA[最小堆]]></category>
		<category><![CDATA[概率]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[随机数]]></category>
		<category><![CDATA[随机选取]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1134</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/colorpicker_weight_2.png" class="attachment-post-thumbnail wp-post-image" alt="colorpicker_weight_2" title="colorpicker_weight_2" /></div>本文介绍一个有趣的算法，用来解决带权随机选取问题：有一组数量未知的数据，每个元素有非负权重。要求只遍历一次，随机选取其中的一个元素，任何一个元素被选到的概率与其权重成正比。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/colorpicker_weight_2.png" class="attachment-post-thumbnail wp-post-image" alt="colorpicker_weight_2" title="colorpicker_weight_2" /></div><p>还是同样的问题：有一组数量未知的数据，每个元素有非负权重。要求只遍历一次，随机选取其中的一个元素，任何一个元素被选到的概率与其权重成正比。</p>
<p>在<a href="http://www.gocalf.com/blog/weighted-random-selection.html">前一篇</a>文章中介绍了概率分布的理论值，并用比较简洁高效的函数实现了选取一个元素的方法。现在来看一个神奇的算法，以及相关的证明和实现。<span id="more-1134"></span></p>
<p>算法很简单：对于任意的i（<code class="codecolorer text geshi"><span class="text">1 &lt;= i &lt;= n</span></code>），按照如下方法给第i个元素分配一个键值key（其中r<sub>i</sub>是一个0到1之间等概率分布的随机数）：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_154ae8747530dca61461c043c2bdb2e2.gif' style='vertical-align: middle; border: none; ' class='tex' alt="key(i)=r_i^{1/w_i}" title="key(i)=r_i^{1/w_i}" /></span><script type='math/tex'>key(i)=r_i^{1/w_i}</script></p>
<p>之后，如果要随机选取一个元素，就去key最大的那个；如果要选取m个元素，就取key最大的m个。</p>
<p>真不知道是怎么想出来的这样的方法，不过还是先来关注一下证明的过程。</p>
<h3>m=1证明</h3>
<p>对于m=1的证明过程会介绍得详细些，主要是怕我自己过几天就忘记了。概率达人可以直接秒杀之。</p>
<p>m=1时，第i个元素被选取到的概率，就等于它所对应的键值key(i)是最大值的概率，即：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_341dfa57ab1384c2b947e332b431e928.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p_i=p(\forall j\neq i,key(j) < key(i))" title="p_i=p(\forall j\neq i,key(j) < key(i))" /></span><script type='math/tex'>p_i=p(\forall j\neq i,key(j) < key(i))</script></p>
<p>把key(i)的计算公式代入，但要注意公式中的r<sub>i</sub>并不是一个固定的数值，而是随机变量。不考虑计算机数值表示的精度，可以假设r<sub>i</sub>是一个在0到1之间的连续均匀概率分布，因此如果要计算key(i)是最大的概率，必须要对r<sub>i</sub>所有的可能值进行概率累加，也就是积分。于是上面的概率表达式就被写成：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_fe15a9b052beee28e585f337117381dc.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p_i=\int_0^1p(\forall j\neq i,r_j^{1/w_j} < r_i^{1/w_i})\mathrm{d}r_i" title="p_i=\int_0^1p(\forall j\neq i,r_j^{1/w_j} < r_i^{1/w_i})\mathrm{d}r_i" /></span><script type='math/tex'>p_i=\int_0^1p(\forall j\neq i,r_j^{1/w_j} < r_i^{1/w_i})\mathrm{d}r_i</script></p>
<p>再看式子中的<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_8b141f94d4371ad99206ca92a896986d.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="\forall" title="\forall" /></span><script type='math/tex'>\forall</script>，它表示每一个j都要满足后面的条件，而各个j之间相互独立，因此可以写成概率乘积，于是得到：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_628c8445aecf85a929a6b178daa24764.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p_i=\int_0^1\prod_{j\neq i}{p(r_j^{1/w_j} < r_i^{1/w_i})}\mathrm{d}r_i" title="p_i=\int_0^1\prod_{j\neq i}{p(r_j^{1/w_j} < r_i^{1/w_i})}\mathrm{d}r_i" /></span><script type='math/tex'>p_i=\int_0^1\prod_{j\neq i}{p(r_j^{1/w_j} < r_i^{1/w_i})}\mathrm{d}r_i</script></p>
<p>对于给定的j，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_d694b4328ccdef70578f635ff6d3419f.gif' style='vertical-align: middle; border: none; ' class='tex' alt="r_j^{1/w_j} < r_i^{1/w_i}\Rightarrow r_j < r_i^{w_j/w_i}" title="r_j^{1/w_j} < r_i^{1/w_i}\Rightarrow r_j < r_i^{w_j/w_i}" /></span><script type='math/tex'>r_j^{1/w_j} < r_i^{1/w_i}\Rightarrow r_j < r_i^{w_j/w_i}</script>，另外r<sub>j</sub>也是个均匀概率分布，将概率密度函数代入可以得到：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_551c9180525dc58ed1f0bb8a0f956d36.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p(r_j < r_i^{w_j/w_i})=\int_0^{r_i^{w_j/w_i}}1\mathrm{d}r_j=r_i^{w_j/w_i}" title="p(r_j < r_i^{w_j/w_i})=\int_0^{r_i^{w_j/w_i}}1\mathrm{d}r_j=r_i^{w_j/w_i}" /></span><script type='math/tex'>p(r_j < r_i^{w_j/w_i})=\int_0^{r_i^{w_j/w_i}}1\mathrm{d}r_j=r_i^{w_j/w_i}</script></p>
<p>因此，上面的概率算式就变成（其中w就是前一篇文章中提到的所有元素的权重之和）：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_61be9db7bf5befc9335f2230185416ec.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p_i=\int_0^1\prod_{j\neq i}{r_i^{w_j/w_i}}\mathrm{d}r_i=\int_0^1r_i^{(w-w_i)/w_i}\mathrm{d}r_i=\frac{w_i}{w}" title="p_i=\int_0^1\prod_{j\neq i}{r_i^{w_j/w_i}}\mathrm{d}r_i=\int_0^1r_i^{(w-w_i)/w_i}\mathrm{d}r_i=\frac{w_i}{w}" /></span><script type='math/tex'>p_i=\int_0^1\prod_{j\neq i}{r_i^{w_j/w_i}}\mathrm{d}r_i=\int_0^1r_i^{(w-w_i)/w_i}\mathrm{d}r_i=\frac{w_i}{w}</script></p>
<p>最后的结果跟<a href="http://www.gocalf.com/blog/weighted-random-selection.html">前一篇</a>文章中的理论值相等，证明完毕。</p>
<h3>m>=1证明</h3>
<p>当m取任意值时，概率公式变得非常复杂，在前一篇文章中使用了第i个元素不被选到的概率来简化表达式。现在的证明也从同样的角度进行。</p>
<p>第i个元素不被选到的概率，显然等于这n个元素中，至少存在m个元素的键值大于key(i)，与之前的讨论一样，不妨设这m个元素的下标（按键值从大到小）依次为j<sub>1</sub>, j<sub>2</sub>, ..., j<sub>m</sub>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_eef8145fd71a457dca49a42129cb902a.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\forall 1\leq k\leq m,j_k\notin\{i,j_1,j_2,\cdots,j_{k-1}\}" title="\forall 1\leq k\leq m,j_k\notin\{i,j_1,j_2,\cdots,j_{k-1}\}" /></span><script type='math/tex'>\forall 1\leq k\leq m,j_k\notin\{i,j_1,j_2,\cdots,j_{k-1}\}</script>，满足<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_e3aeba92d455042f3da63447aec921c7.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\forall 1\leq t_k\leq n,t_k\notin\{j_1,j_2,\cdots,j_{k}\},key(j_k) > key(t_k)" title="\forall 1\leq t_k\leq n,t_k\notin\{j_1,j_2,\cdots,j_{k}\},key(j_k) > key(t_k)" /></span><script type='math/tex'>\forall 1\leq t_k\leq n,t_k\notin\{j_1,j_2,\cdots,j_{k}\},key(j_k) > key(t_k)</script>。注意j<sub>k</sub>和t<sub>k</sub>的取值范围，为了简单起见，下面的式子中就不再重复了。</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_7d913ee9de67712b9abbd8812c115707.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\bar{p}_i(m)=p(\exists j_1,j_2,...,j_m\neq i,key(j_1) > key(j_2) > ... > key(j_m) > key(i))" title="\bar{p}_i(m)=p(\exists j_1,j_2,...,j_m\neq i,key(j_1) > key(j_2) > ... > key(j_m) > key(i))" /></span><script type='math/tex'>\bar{p}_i(m)=p(\exists j_1,j_2,...,j_m\neq i,key(j_1) > key(j_2) > ... > key(j_m) > key(i))</script></p>
<p>为了能够进一步求解，必须把这个连等式拆开。这里要非常小心，各个j<sub>k</sub>并不是相互独立的，比如当j<sub>1</sub>改变的时候，j<sub>2</sub>的取值范围也会随之变化，依此类推。拆开之后的式子如下：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_34bbea1211ca7cbae6c00253070f069b.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{array}{rrrl}\bar{p}_i(m)=p( & \exists j_1( & & \forall t_1,key(j_1) > key(t_1),\\ & & \exists j_2( & \forall t_2,key(j_2) > key(t_2),\\ & & & ...,\\ & & & \exists j_m(\forall t_m,key(j_m) > key(t_m))\\ & & ) & \\ & ) & & \\ ) & & & \end{array}" title="\begin{array}{rrrl}\bar{p}_i(m)=p( & \exists j_1( & & \forall t_1,key(j_1) > key(t_1),\\ & & \exists j_2( & \forall t_2,key(j_2) > key(t_2),\\ & & & ...,\\ & & & \exists j_m(\forall t_m,key(j_m) > key(t_m))\\ & & ) & \\ & ) & & \\ ) & & & \end{array}" /></span><script type='math/tex'>\begin{array}{rrrl}\bar{p}_i(m)=p( & \exists j_1( & & \forall t_1,key(j_1) > key(t_1),\\ & & \exists j_2( & \forall t_2,key(j_2) > key(t_2),\\ & & & ...,\\ & & & \exists j_m(\forall t_m,key(j_m) > key(t_m))\\ & & ) & \\ & ) & & \\ ) & & & \end{array}</script></p>
<p>看起来还是相当恐怖的，一层套一层。注意等式右边已经没有显式地关于i的信息了，这些信息被隐含在j<sub>k</sub>和t<sub>k</sub>的取值范围中，切记。对每个j<sub>k</sub>，把key(j<sub>k</sub>)的式子代进去，转换成积分；同时把<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_1d6cb208d7cc185173c531aadae61616.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\forall t_k" title="\forall t_k" /></span><script type='math/tex'>\forall t_k</script>转换为<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_fb2ab9454a677c65793091e1c3c2c57f.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\prod_{t_k}" title="\prod_{t_k}" /></span><script type='math/tex'>\prod_{t_k}</script>。这些在m=1的证明中都提到过了。新出现的是<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_c180b0a1b5a67799e9d37ca980718839.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\exists j_k" title="\exists j_k" /></span><script type='math/tex'>\exists j_k</script>，这个显然适用概率加法，因为j<sub>k</sub>取不同的值对应于不同的互斥方案。经过这些变换得到：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_8a5b1118c47ba134945cdafe220b24f9.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{array}{rrrl}\bar{p}_i(m)= & \sum_{j_1}( & & \int_0^1\prod_{t_1}p(r_{j_1}^{1/w_{j_1}} > r_{t_1}^{1/w_{t_1}})\mathrm{d}r_{j_1}\times\\ & & \sum_{j_2}( & \int_0^1\prod_{t_2} p(r_{j_2}^{1/w_{j_2}} > r_{t_2}^{1/w_{t_2}})\mathrm{d}r_{j_2}\times\\ & & & ...\times\\ & & & \sum_{j_m}(\int_0^1\prod_{t_m} p(r_{j_m}^{1/w_{j_m}} > r_{t_m}^{1/w_{t_m}})\mathrm{d}r_{j_m})\\ & & ) & \\ & ) & & \\ \end{array}" title="\begin{array}{rrrl}\bar{p}_i(m)= & \sum_{j_1}( & & \int_0^1\prod_{t_1}p(r_{j_1}^{1/w_{j_1}} > r_{t_1}^{1/w_{t_1}})\mathrm{d}r_{j_1}\times\\ & & \sum_{j_2}( & \int_0^1\prod_{t_2} p(r_{j_2}^{1/w_{j_2}} > r_{t_2}^{1/w_{t_2}})\mathrm{d}r_{j_2}\times\\ & & & ...\times\\ & & & \sum_{j_m}(\int_0^1\prod_{t_m} p(r_{j_m}^{1/w_{j_m}} > r_{t_m}^{1/w_{t_m}})\mathrm{d}r_{j_m})\\ & & ) & \\ & ) & & \\ \end{array}" /></span><script type='math/tex'>\begin{array}{rrrl}\bar{p}_i(m)= & \sum_{j_1}( & & \int_0^1\prod_{t_1}p(r_{j_1}^{1/w_{j_1}} > r_{t_1}^{1/w_{t_1}})\mathrm{d}r_{j_1}\times\\ & & \sum_{j_2}( & \int_0^1\prod_{t_2} p(r_{j_2}^{1/w_{j_2}} > r_{t_2}^{1/w_{t_2}})\mathrm{d}r_{j_2}\times\\ & & & ...\times\\ & & & \sum_{j_m}(\int_0^1\prod_{t_m} p(r_{j_m}^{1/w_{j_m}} > r_{t_m}^{1/w_{t_m}})\mathrm{d}r_{j_m})\\ & & ) & \\ & ) & & \\ \end{array}</script></p>
<p>其中的积分式在之前已经见过了，其运算过程如下（注意t<sub>k</sub>的取值范围）：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_a35539066de845d0cedf530751e1e4c2.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{array}{rl} & \int_0^1\prod_{t_k}p(r_{j_k}^{1/w_{j_k}} > _{t_k}^{1/w_{t_k}})\mathrm{d}r_{j_k} \\ & \\ = & \int_0^1\prod_{t_k}r_{j_k}^{w_{t_k}/w_{j_k}}\mathrm{d}r_{j_k} \\ & \\ = & \int_0^1r_{j_k}^{(\sum_{t_k}w_{t_k})/w_{j_k}}\mathrm{d}r_{j_k} \\ & \\ = & \frac{w_{j_k}}{(\sum_{t_k}w_{t_k})+w_{j_k}} \\ & \\ = & \frac{w_{j_k}}{w-(w_{j_1}+w_{j_2}+...+w_{j_{k-1}})} \end{array}" title="\begin{array}{rl} & \int_0^1\prod_{t_k}p(r_{j_k}^{1/w_{j_k}} > _{t_k}^{1/w_{t_k}})\mathrm{d}r_{j_k} \\ & \\ = & \int_0^1\prod_{t_k}r_{j_k}^{w_{t_k}/w_{j_k}}\mathrm{d}r_{j_k} \\ & \\ = & \int_0^1r_{j_k}^{(\sum_{t_k}w_{t_k})/w_{j_k}}\mathrm{d}r_{j_k} \\ & \\ = & \frac{w_{j_k}}{(\sum_{t_k}w_{t_k})+w_{j_k}} \\ & \\ = & \frac{w_{j_k}}{w-(w_{j_1}+w_{j_2}+...+w_{j_{k-1}})} \end{array}" /></span><script type='math/tex'>\begin{array}{rl} & \int_0^1\prod_{t_k}p(r_{j_k}^{1/w_{j_k}} > _{t_k}^{1/w_{t_k}})\mathrm{d}r_{j_k} \\ & \\ = & \int_0^1\prod_{t_k}r_{j_k}^{w_{t_k}/w_{j_k}}\mathrm{d}r_{j_k} \\ & \\ = & \int_0^1r_{j_k}^{(\sum_{t_k}w_{t_k})/w_{j_k}}\mathrm{d}r_{j_k} \\ & \\ = & \frac{w_{j_k}}{(\sum_{t_k}w_{t_k})+w_{j_k}} \\ & \\ = & \frac{w_{j_k}}{w-(w_{j_1}+w_{j_2}+...+w_{j_{k-1}})} \end{array}</script></p>
<p>最终，概率计算式子变成：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_c253ece406445911e2604e7de1a163d5.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\bar{p}_i(m)=\sum_{j_1}\left(\frac{w_{j_1}}{w}\sum_{j_2}\left(\frac{w_{j_2}}{w-w_{j_1}}\sum_{j_3}\left(\frac{w_{j_2}}{w-w_{j_1}-w_{j_2}}\cdots\sum_{j_m}\frac{w_{j_m}}{w-\sum_{k=1}^{m-1}w_{j_k}}\right)\right)\right)" title="\bar{p}_i(m)=\sum_{j_1}\left(\frac{w_{j_1}}{w}\sum_{j_2}\left(\frac{w_{j_2}}{w-w_{j_1}}\sum_{j_3}\left(\frac{w_{j_2}}{w-w_{j_1}-w_{j_2}}\cdots\sum_{j_m}\frac{w_{j_m}}{w-\sum_{k=1}^{m-1}w_{j_k}}\right)\right)\right)" /></span><script type='math/tex'>\bar{p}_i(m)=\sum_{j_1}\left(\frac{w_{j_1}}{w}\sum_{j_2}\left(\frac{w_{j_2}}{w-w_{j_1}}\sum_{j_3}\left(\frac{w_{j_2}}{w-w_{j_1}-w_{j_2}}\cdots\sum_{j_m}\frac{w_{j_m}}{w-\sum_{k=1}^{m-1}w_{j_k}}\right)\right)\right)</script></p>
<p>与<a href="http://www.gocalf.com/blog/weighted-random-selection.html">前一篇</a>文章中的理论值完全一样。</p>
<p>呼，可怕的推导过程。</p>
<h3>程序实现</h3>
<p>虽然证明过程异常恐怖，但实现起来却很简单。实际运算中，只要维持一个大小为m的最小堆（没错，是最小堆）来保存当前已知的最大的m个键值，每拿到一个新的元素，算出对应的键值，如果它比堆中的最小值大，就可以放入堆中替换掉最小值。Python实现函数如下：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">random</span> <span style="color: #ff7700;font-weight:bold;">import</span> Random<br />
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">heapq</span> <span style="color: #ff7700;font-weight:bold;">import</span> *<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> WeightedRandomSample<span style="color: black;">&#40;</span>m<span style="color: #66cc66;">=</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> rand<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> m <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'invalid m'</span><br />
&nbsp; selection <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; heap <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> rand <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; rand <span style="color: #66cc66;">=</span> Random<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Outputs the current selection and gets next item</span><br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>item<span style="color: #66cc66;">,</span> weight<span style="color: black;">&#41;</span> <span style="color: #66cc66;">=</span> <span style="color: #ff7700;font-weight:bold;">yield</span> selection<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> weight <span style="color: #66cc66;">&lt;=</span> <span style="color: #ff4500;">0</span>: <span style="color: #ff7700;font-weight:bold;">continue</span><br />
&nbsp; &nbsp; key <span style="color: #66cc66;">=</span> rand.<span style="color: #dc143c;">random</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> ** <span style="color: black;">&#40;</span><span style="color: #ff4500;">1.0</span> / weight<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>selection<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&lt;</span> m:<br />
&nbsp; &nbsp; &nbsp; heap.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>key<span style="color: #66cc66;">,</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>selection<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; selection.<span style="color: black;">append</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>selection<span style="color: black;">&#41;</span> <span style="color: #66cc66;">==</span> m:<br />
&nbsp; &nbsp; &nbsp; &nbsp; heapify<span style="color: black;">&#40;</span>heap<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> key <span style="color: #66cc66;">&gt;</span> heap<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; index <span style="color: #66cc66;">=</span> heap<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; heapreplace<span style="color: black;">&#40;</span>heap<span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span>key<span style="color: #66cc66;">,</span> index<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; selection<span style="color: black;">&#91;</span>index<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> item</div></td></tr></tbody></table></div></pre>
<p>每次拿到一个新的元素，通过<code class="codecolorer python geshi"><span class="python">key <span style="color: #66cc66;">=</span> rand.<span style="color: #dc143c;">random</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> ** <span style="color: black;">&#40;</span><span style="color: #ff4500;">1.0</span> / weight<span style="color: black;">&#41;</span></span></code>产生一个与其权重有关的随机键值key。当元素个数小于m时，直接将新的元素放入堆空间中（但并不建堆），这样只用O(1)时间；当遇到第m个元素后，堆空间放满了，这时候进行建堆操作（<code class="codecolorer python geshi"><span class="python">heapify<span style="color: black;">&#40;</span>heap<span style="color: black;">&#41;</span></span></code>），需要O(m)时间；之后每拿到一个新的元素，用O(1)时间从堆顶拿出最小值与新元素的键值比较，如果后者更大就用后者替换掉堆顶元素，对堆进行必要的操作（O(log m)时间）以保持其结构（<code class="codecolorer python geshi"><span class="python">heapreplace<span style="color: black;">&#40;</span>heap<span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span>key<span style="color: #66cc66;">,</span> index<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></span></code>）。</p>
<p>关于Python中的堆可以参考：<a href="http://docs.python.org/library/heapq.html" target="_blank">http://docs.python.org/library/heapq.html</a>。</p>
<p>总体来看，整段程序用时O(n * log m)，占用O(m)辅助空间。这样的处理比较适用于<code class="codecolorer text geshi"><span class="text">m &lt;&lt; n</span></code>的情况。当m与n接近时，可以用n个辅助空间存储所有元素的键值，当遍历结束后用O(n)时间对这n个元素执行快速选择算法，选出m个最大的元素即可，耗时O(n)，辅助空间O(n)。</p>
<p>用同样一组具有等差分布权重的元素调用WeightedRandomSample十万次，得到如下的概率分布，与理论分布非常接近。</p>
<div id="attachment_1173" class="wp-caption alignnone" style="width: 663px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/weighted_sample_p.png" alt="weighted_sample_p" title="weighted_sample_p" width="653" height="419" class="size-full wp-image-1173 wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">用WeightedRandomSample函数随机选取m个元素，第i个元素被选中的概率</p></div>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
<li><a href='http://www.gocalf.com/blog/random-selection.html' rel='bookmark' title='单次遍历，等概率随机选取问题'>单次遍历，等概率随机选取问题</a></li>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
<li><a href='http://www.gocalf.com/blog/shuffle-algo.html' rel='bookmark' title='等概率随机排列数组（洗牌算法）'>等概率随机排列数组（洗牌算法）</a></li>
<li><a href='http://www.gocalf.com/blog/algorithm-complexity-and-master-theorem.html' rel='bookmark' title='算法的复杂度与Master定理'>算法的复杂度与Master定理</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/weighted-random-selection-2.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>单次遍历，带权随机选取问题（一）</title>
		<link>http://www.gocalf.com/blog/weighted-random-selection.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=weighted-random-selection</link>
		<comments>http://www.gocalf.com/blog/weighted-random-selection.html#comments</comments>
		<pubDate>Wed, 21 Sep 2011 15:07:37 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Random Sample]]></category>
		<category><![CDATA[Random Selection]]></category>
		<category><![CDATA[Weighted Random Sample]]></category>
		<category><![CDATA[Weighted Selection]]></category>
		<category><![CDATA[单次遍历]]></category>
		<category><![CDATA[带权概率]]></category>
		<category><![CDATA[概率]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[随机数]]></category>
		<category><![CDATA[随机选取]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1085</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/colorpicker_weight.png" class="attachment-post-thumbnail wp-post-image" alt="colorpicker_weight" title="colorpicker_weight" /></div>问题描述：有一组数量未知的数据，每个元素有非负权重。要求只遍历一次，随机选取其中的一个元素，任何一个元素被选到的概率与其权重成正比。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/colorpicker_weight.png" class="attachment-post-thumbnail wp-post-image" alt="colorpicker_weight" title="colorpicker_weight" /></div><p>在<a href="http://www.gocalf.com/blog/random-selection.html">单次遍历，等概率随机选取问题</a>中已经剧透了今天的内容，那就是带权随机选取（Weighted Random Sample）问题。</p>
<p>问题描述：有一组数量未知的数据，每个元素有非负权重。要求只遍历一次，随机选取其中的一个元素，任何一个元素被选到的概率与其权重成正比。<span id="more-1085"></span></p>
<p>设元素总数为n，当然在遍历结束前n是未知的。设第i（<code class="codecolorer text geshi"><span class="text">1 &lt;= i &lt;= n</span></code>）个元素的权重为w<sub>i</sub>（> 0），则权重总和为<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_6854062b9d0bb50b35e2a577eeb45726.gif' style='vertical-align: middle; border: none; ' class='tex' alt="w=\sum_{i=1}^{n}{w_i}" title="w=\sum_{i=1}^{n}{w_i}" /></span><script type='math/tex'>w=\sum_{i=1}^{n}{w_i}</script>，也是在遍历结束时才知道的。根据题目要求，第i个元素被选取的概率应该等于<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_af5abde27b462f655e8f6b0aefbc40c8.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p_i=\frac{w_i}{w}" title="p_i=\frac{w_i}{w}" /></span><script type='math/tex'>p_i=\frac{w_i}{w}</script>。</p>
<p>虽然加了个权重，但解法依旧非常简单，在<a href="http://www.gocalf.com/blog/random-selection.html">单次遍历，等概率随机选取问题</a>中的RandomSelect函数上稍作修改就得到本问题的解法，依旧是O(n)时间，O(1)辅助空间：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">random</span> <span style="color: #ff7700;font-weight:bold;">import</span> Random<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> WeightedRandomSelect<span style="color: black;">&#40;</span>rand<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:<br />
&nbsp; selection <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><br />
&nbsp; totalweight <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0.0</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> rand <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; rand <span style="color: #66cc66;">=</span> Random<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Outputs the current selection and gets next item</span><br />
&nbsp; &nbsp; <span style="color: black;">&#40;</span>item<span style="color: #66cc66;">,</span> weight<span style="color: black;">&#41;</span> <span style="color: #66cc66;">=</span> <span style="color: #ff7700;font-weight:bold;">yield</span> selection<br />
&nbsp; &nbsp; totalweight +<span style="color: #66cc66;">=</span> weight<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> rand.<span style="color: #dc143c;">random</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> * totalweight <span style="color: #66cc66;">&lt;</span> weight:<br />
&nbsp; &nbsp; &nbsp; selection <span style="color: #66cc66;">=</span> item</div></td></tr></tbody></table></div></pre>
<p>其中Python的<code class="codecolorer python geshi"><span class="python"><span style="color: #dc143c;">random</span>.<span style="color: #dc143c;">random</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></span></code>返回[0, 1)之间的随机小数。</p>
<p>看一下是否满足概率要求。如果最终被选取的是第i（<code class="codecolorer text geshi"><span class="text">1 &lt;= i &lt;= n</span></code>）个元素，那必须是遍历到它的时候，恰好被选中，即<code class="codecolorer python geshi"><span class="python">rand.<span style="color: #dc143c;">random</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> * totalweight <span style="color: #66cc66;">&lt;</span> weight</span></code>，其概率为：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_15b60c1756556668feb48d4802b85137.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\frac{w_i}{w}=\frac{w_i}{\sum_{k=1}^{i}{w_k}}" title="\frac{w_i}{w}=\frac{w_i}{\sum_{k=1}^{i}{w_k}}" /></span><script type='math/tex'>\frac{w_i}{w}=\frac{w_i}{\sum_{k=1}^{i}{w_k}}</script></p>
<p>另外，还要在处理以后的任何一个元素时，第i个元素都没有被替换掉，即对于任意的j（<code class="codecolorer text geshi"><span class="text">i &lt; j &lt;= n</span></code>），第j个元素都不会被选中，其概率为：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_4d0621e5edc0db8b56a4cde27957e9af.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\frac{w-w_j}{w}=\frac{\sum_{k=1}^{j-1}{w_k}}{\sum_{k=1}^{j}{w_k}}" title="\frac{w-w_j}{w}=\frac{\sum_{k=1}^{j-1}{w_k}}{\sum_{k=1}^{j}{w_k}}" /></span><script type='math/tex'>\frac{w-w_j}{w}=\frac{\sum_{k=1}^{j-1}{w_k}}{\sum_{k=1}^{j}{w_k}}</script></p>
<p>因此，第i个元素最终被选取的概率为：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_649dd342a7f5d4ea84fa8525ef3bc4dd.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p_i=\frac{w_i}{\sum_{k=1}^{i}{w_k}}\times\frac{\sum_{k=1}^{i}{w_k}}{\sum_{k=1}^{i+1}{w_k}}\times\frac{\sum_{k=1}^{i+1}{w_k}}{\sum_{k=1}^{i+2}{w_k}}\times\cdots\times\frac{\sum_{k=1}^{n-1}{w_k}}{\sum_{k=1}^{n}{w_k}}=\frac{w_i}{\sum_{k=1}^{n}{w_k}}" title="p_i=\frac{w_i}{\sum_{k=1}^{i}{w_k}}\times\frac{\sum_{k=1}^{i}{w_k}}{\sum_{k=1}^{i+1}{w_k}}\times\frac{\sum_{k=1}^{i+1}{w_k}}{\sum_{k=1}^{i+2}{w_k}}\times\cdots\times\frac{\sum_{k=1}^{n-1}{w_k}}{\sum_{k=1}^{n}{w_k}}=\frac{w_i}{\sum_{k=1}^{n}{w_k}}" /></span><script type='math/tex'>p_i=\frac{w_i}{\sum_{k=1}^{i}{w_k}}\times\frac{\sum_{k=1}^{i}{w_k}}{\sum_{k=1}^{i+1}{w_k}}\times\frac{\sum_{k=1}^{i+1}{w_k}}{\sum_{k=1}^{i+2}{w_k}}\times\cdots\times\frac{\sum_{k=1}^{n-1}{w_k}}{\sum_{k=1}^{n}{w_k}}=\frac{w_i}{\sum_{k=1}^{n}{w_k}}</script></p>
<p>下面这段程序调用WeightedRandomSelect对一组具有等差数列权重的元素进行选取。</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;"># Sample code to use WeightedRandomSelect function</span><br />
<span style="color: #808080; font-style: italic;"># Use an arithmetic sequence as weights</span><br />
n <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">10</span><br />
<span style="color: #808080; font-style: italic;"># weights are [1, 2, 3, ..., 10]</span><br />
weights <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>i + <span style="color: #ff4500;">1</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
repeat <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">100000</span><br />
occurrences <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
rand <span style="color: #66cc66;">=</span> Random<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>repeat<span style="color: black;">&#41;</span>:<br />
&nbsp; selector <span style="color: #66cc66;">=</span> WeightedRandomSelect<span style="color: black;">&#40;</span>rand<span style="color: black;">&#41;</span><br />
&nbsp; selector.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; selection <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> item <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; selection <span style="color: #66cc66;">=</span> selector.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>item<span style="color: #66cc66;">,</span> weights<span style="color: black;">&#91;</span>item<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; occurrences<span style="color: black;">&#91;</span>selection<span style="color: black;">&#93;</span> +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
<span style="color: #ff7700;font-weight:bold;">print</span> occurrences</div></td></tr></tbody></table></div></pre>
<p>某次运行结果为：</p>
<pre><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[1723, 3644, 5405, 7326, 9027, 10903, 12678, 14784, 16345, 18165]</div></div></pre>
<p>而对于这组权重的概率理论值为：</p>
<pre><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10<br />
= 0.0181818 : 0.0363636 : 0.0545455 : 0.0727273 : 0.0909091 : 0.109091 : 0.127273 : 0.145455 : 0.163636 : 0.181818</div></div></pre>
<p>可见程序是正确的。</p>
<h3>扩展：选取m个元素，概率理论值</h3>
<p>来看看选取多个元素的问题。当选取多个元素时，可以认为选取过程是逐步进行的，即无放回的多次选取。每一次选取时，任何一个元素被选中的概率都与其权重成正比，但总的权重则又剩余的元素集合决定。</p>
<p>当m=2的时候，第i个元素被选中可以是两种情况：第一次就被选中；第一次未被选中，第二次被选中。可以得到其概率为这两种情况的概率之和，即：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_a1a077986a0f942fde87158886af23b3.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p_i(2)=\frac{w_i}{w}+\sum_{j\neq i}\left(\frac{w_j}{w}\times\frac{w_i}{w-w_j}\right)" title="p_i(2)=\frac{w_i}{w}+\sum_{j\neq i}\left(\frac{w_j}{w}\times\frac{w_i}{w-w_j}\right)" /></span><script type='math/tex'>p_i(2)=\frac{w_i}{w}+\sum_{j\neq i}\left(\frac{w_j}{w}\times\frac{w_i}{w-w_j}\right)</script></p>
<p>值得注意的是，即便w<sub>i</sub>和w不变，如果其他元素的概率分布不同，最后得到的结果也不同，因此上面这个式子无法把其中的求和化简掉。</p>
<p>从另一方面来看，第i个元素被选中的概率等于1减去它不被选中的概率。用<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_fbe8494b458b87e09b6d97195bb3ba4a.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\bar{p}" title="\bar{p}" /></span><script type='math/tex'>\bar{p}</script>表示不被选中的概率，则有：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_00b4c66c3f74a0552d8567b1d137a84a.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\bar{p}_i(2)=\sum_{j\neq i}\left(\frac{w_j}{w}\times\frac{w-w_j-w_i}{w-w_j}\right)" title="\bar{p}_i(2)=\sum_{j\neq i}\left(\frac{w_j}{w}\times\frac{w-w_j-w_i}{w-w_j}\right)" /></span><script type='math/tex'>\bar{p}_i(2)=\sum_{j\neq i}\left(\frac{w_j}{w}\times\frac{w-w_j-w_i}{w-w_j}\right)</script></p>
<p>显然，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_6c5b98650baaf05fc83e7d99d71799b7.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p_i(2)+\bar{p}_i(2)=1" title="p_i(2)+\bar{p}_i(2)=1" /></span><script type='math/tex'>p_i(2)+\bar{p}_i(2)=1</script>。</p>
<p>当m>2时，其概率表达式将会变得异常复杂，因为跟概率分布有关，所以算式无法化简。未被选中的概率计算式要稍微简单些，大概是这个样子的：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_c253ece406445911e2604e7de1a163d5.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\bar{p}_i(m)=\sum_{j_1}\left(\frac{w_{j_1}}{w}\sum_{j_2}\left(\frac{w_{j_2}}{w-w_{j_1}}\sum_{j_3}\left(\frac{w_{j_2}}{w-w_{j_1}-w_{j_2}}\cdots\sum_{j_m}\frac{w_{j_m}}{w-\sum_{k=1}^{m-1}w_{j_k}}\right)\right)\right)" title="\bar{p}_i(m)=\sum_{j_1}\left(\frac{w_{j_1}}{w}\sum_{j_2}\left(\frac{w_{j_2}}{w-w_{j_1}}\sum_{j_3}\left(\frac{w_{j_2}}{w-w_{j_1}-w_{j_2}}\cdots\sum_{j_m}\frac{w_{j_m}}{w-\sum_{k=1}^{m-1}w_{j_k}}\right)\right)\right)" /></span><script type='math/tex'>\bar{p}_i(m)=\sum_{j_1}\left(\frac{w_{j_1}}{w}\sum_{j_2}\left(\frac{w_{j_2}}{w-w_{j_1}}\sum_{j_3}\left(\frac{w_{j_2}}{w-w_{j_1}-w_{j_2}}\cdots\sum_{j_m}\frac{w_{j_m}}{w-\sum_{k=1}^{m-1}w_{j_k}}\right)\right)\right)</script></p>
<p>其中，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_eef8145fd71a457dca49a42129cb902a.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\forall 1\leq k\leq m,j_k\notin\{i,j_1,j_2,\cdots,j_{k-1}\}" title="\forall 1\leq k\leq m,j_k\notin\{i,j_1,j_2,\cdots,j_{k-1}\}" /></span><script type='math/tex'>\forall 1\leq k\leq m,j_k\notin\{i,j_1,j_2,\cdots,j_{k-1}\}</script>。</p>
<p>对于给定的一组权重，可以用下面这段程序计算出任意m、i（程序中的i是从0开始的）对应的概率数值（请无视其coding style）：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> Foo<span style="color: black;">&#40;</span>weights<span style="color: #66cc66;">,</span> ids<span style="color: #66cc66;">,</span> totalweight<span style="color: #66cc66;">,</span> m<span style="color: #66cc66;">,</span> i<span style="color: #66cc66;">,</span> times<span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> times <span style="color: #66cc66;">==</span> m: <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">1</span><br />
&nbsp; p <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0.0</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> ids:<br />
&nbsp; &nbsp; ids.<span style="color: black;">remove</span><span style="color: black;">&#40;</span>j<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; p +<span style="color: #66cc66;">=</span> <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>weights<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> / totalweight \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* Foo<span style="color: black;">&#40;</span>weights<span style="color: #66cc66;">,</span> ids<span style="color: #66cc66;">,</span> totalweight - weights<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> m<span style="color: #66cc66;">,</span> i<span style="color: #66cc66;">,</span> times + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; ids.<span style="color: black;">add</span><span style="color: black;">&#40;</span>j<span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> p<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> CalcSampleProbability<span style="color: black;">&#40;</span>weights<span style="color: #66cc66;">,</span> m<span style="color: #66cc66;">,</span> i<span style="color: black;">&#41;</span>:<br />
&nbsp; n <span style="color: #66cc66;">=</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>weights<span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> <span style="color: #ff4500;">0</span> <span style="color: #66cc66;">&lt;=</span> i <span style="color: #66cc66;">&lt;</span> n<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'invalid i'</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">assert</span> <span style="color: #ff4500;">0</span> <span style="color: #66cc66;">&lt;</span> m <span style="color: #66cc66;">&lt;=</span> n<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'invalid m'</span><br />
&nbsp; ids <span style="color: #66cc66;">=</span> <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; ids.<span style="color: black;">remove</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span><br />
&nbsp; p <span style="color: #66cc66;">=</span> Foo<span style="color: black;">&#40;</span>weights<span style="color: #66cc66;">,</span> ids<span style="color: #66cc66;">,</span> <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span>weights<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> m<span style="color: #66cc66;">,</span> i<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">1</span> - p</div></td></tr></tbody></table></div></pre>
<p>可惜算法的复杂度非常高，CalcSampleProbability需要O(n^m)时间来完成一次计算。期待高手改进。</p>
<p>来看一下等权重、等差数列权重和等比数列权重的n选m概率分布图（图中i依旧采用<code class="codecolorer text geshi"><span class="text">1 &lt;= i &lt;= n</span></code>的取值范围）：</p>
<div id="attachment_1113" class="wp-caption alignnone" style="width: 663px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/sample_p_equal.png" alt="sample_p_equal" title="sample_p_equal" width="653" height="419" class="size-full wp-image-1113 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">等值权重随机选取m个元素，第i个元素被选中的概率</p></div>
<p>&nbsp;</p>
<div id="attachment_1114" class="wp-caption alignnone" style="width: 663px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/sample_p_arithmetic.png" alt="sample_p_arithmetic" title="sample_p_arithmetic" width="653" height="419" class="size-full wp-image-1114 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">等差分布权重随机选取m个元素，第i个元素被选中的概率</p></div>
<p>&nbsp;</p>
<div id="attachment_1115" class="wp-caption alignnone" style="width: 663px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/sample_p_geometric.png" alt="sample_p_geometric" title="sample_p_geometric" width="653" height="419" class="size-full wp-image-1115 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">等比分布权重随机选取m个元素，第i个元素被选中的概率</p></div>
<p>Mathematica提供了RandomSample函数，支持带权选取，当然它是在遍历之前就已经知道元素个数的。给它一组等差分布的权重，可以看出十万次随机选取后得到的概率分布与上面的理论分布非常接近。</p>
<div id="attachment_1122" class="wp-caption alignnone" style="width: 607px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/mathematica_random_sample.png" alt="mathematica_random_sample" title="mathematica_random_sample" width="597" height="524" class="size-full wp-image-1122 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">Mathematica RandomSample随机选取m个元素，第i个元素被选中的概率</p></div>
<p>苦苦思考了好几天，但并没有想到一个直观的方法可以给之前的RandomSample加上权重处理。因为那概率式子太复杂，实在不知道该怎么去凑。不过在下一篇文章中将会介绍一个神奇的算法（当然不是我想出来的），并且会给出我的证明。</p>
<p>现在发文章的速度越来越慢了，实在因为能力有限，每次为了一两个式子都要演算很久。再接再厉。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection-2.html' rel='bookmark' title='单次遍历，带权随机选取问题（二）'>单次遍历，带权随机选取问题（二）</a></li>
<li><a href='http://www.gocalf.com/blog/random-selection.html' rel='bookmark' title='单次遍历，等概率随机选取问题'>单次遍历，等概率随机选取问题</a></li>
<li><a href='http://www.gocalf.com/blog/shuffle-algo.html' rel='bookmark' title='等概率随机排列数组（洗牌算法）'>等概率随机排列数组（洗牌算法）</a></li>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
<li><a href='http://www.gocalf.com/blog/unbalcanced-coin.html' rel='bookmark' title='利用不均匀硬币产生等概率'>利用不均匀硬币产生等概率</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/weighted-random-selection.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>《塞尔达传说：黎明公主》攻略：初章 英雄传说的扉页</title>
		<link>http://www.gocalf.com/blog/zelda-tp-ch1.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=zelda-tp-ch1</link>
		<comments>http://www.gocalf.com/blog/zelda-tp-ch1.html#comments</comments>
		<pubDate>Tue, 13 Sep 2011 14:59:25 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[游戏]]></category>
		<category><![CDATA[Game]]></category>
		<category><![CDATA[Twilight Princess]]></category>
		<category><![CDATA[Wii]]></category>
		<category><![CDATA[任天堂]]></category>
		<category><![CDATA[塞尔达传说]]></category>
		<category><![CDATA[游戏攻略]]></category>
		<category><![CDATA[黎明公主]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1039</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_logo.jpg" class="attachment-post-thumbnail wp-post-image" alt="tp_ch01_logo" title="tp_ch01_logo" /></div>初章 英雄传说的扉页（被神选中的少年）

如你期望那样，你将扮演Link，拯救Zelda公主和Hyrule王国的年轻英雄。在黎明公主中，你将与横行在Hyrule王国的暗影军团战斗。凭借Hyrule大地神奇的力量和你自己的勇气，在一个个迷宫里消灭无数的敌人吧！那么，现在就开始我们的旅程！]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_logo.jpg" class="attachment-post-thumbnail wp-post-image" alt="tp_ch01_logo" title="tp_ch01_logo" /></div><h3>初章 英雄传说的扉页（被神选中的少年）</h3>
<p>如你期望那样，你将扮演Link，拯救Zelda公主和Hyrule王国的年轻英雄。在黎明公主中，你将与横行在Hyrule王国的暗影军团战斗。凭借Hyrule大地神奇的力量和你自己的勇气，在一个个迷宫里消灭无数的敌人吧！那么，现在就开始我们的旅程！<span id="more-1039"></span></p>
<h4>奥东村（Ordon Village）</h4>
<p>奥东村（Ordon Village）外，法隆森林（Faron Woods）的泉水旁，我们的主角<a href="http://www.gocalf.com/blog/zelda-tp-characters.html#Link">林克（Link）</a>与村里唯一的剑士，也即林克的导师鲁斯尔（Rusl）在谈论着夜晚的异常与广阔的海拉尔（Hyrule）世界，鲁斯尔问林克是否知道黎明之时（Twilight Time），年轻的林克显然还不知道这些，因为他还没走出过法隆森林，鲁斯尔也打算让林克到外面的世界去看看，让他后天把送给贵族的东西到带海拉尔城去。在天黑前两人回到了村子里。</p>
<div id="attachment_1059" class="wp-caption alignnone" style="width: 650px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_01.jpg" alt="tp_ch01_01" title="tp_ch01_01" width="640" height="480" class="size-full wp-image-1059 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">林克与导师鲁斯尔在谈论着夜晚的异常与广阔的海拉尔世界</p></div>
<h5>牧羊</h5>
<p>过了一会，一位村民跑来告诉林克，艾普娜不见了，林克赶到奥东之泉（Ordon Spring），看见了青梅竹马<a href="http://www.gocalf.com/blog/zelda-tp-characters.html#Ilia">伊莉娅（Ilia）</a>与艾普娜，原来是伊莉娅帮林克给艾普娜擦拭干净，伊莉娅告诉林克，艾普娜有点烦躁不安，林克拔起湖边（马蹄状）的草，吹起了悠扬的口哨，艾普娜顿时安静了下来，林克骑上艾普娜，试了一下感觉，真是一匹出色的马驹。回到村里，林克四处逛了一下（与大家说说话吧，不过现在还不能进到任何屋子里），然后来到奥东牧场（Ordon Ranch），农场主请林克帮忙把倔犟的羊群赶回羊圈。完成任务并不困难，赶羊的乐趣大家很快就能体会到了。按A键能惊吓羊支，让它们更快的移动，不过兔子急了也会咬人的哦！小心它们调头攻击你！完成后，农场主提供农场让林克练习骑马跳，在接近栅栏一段距离的时候按A加速，到达栅栏时马会自动跳过去，练习得差不多了，天色也渐渐晚了，林克骑着艾普娜跳过农场大门径直回了家。一天的生活结束了，此时的林克还不知道之后的自己即将要担负起拯救两个世界的重任。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_02.jpg"><div id="attachment_1060" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_02-700x466.jpg" alt="tp_ch01_02" title="tp_ch01_02" width="700" height="466" class="size-large wp-image-1060 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">奥东牧场的农场主请林克帮忙把倔犟的羊群赶回羊圈</p></div></a></p>
<h5>孕妇的篮子，离家出走的猫</h5>
<p>第二天一早，林克被村里的小孩们给叫醒了，本来打算骑着艾普娜到处逛一下的，但是鲁斯尔的儿子柯林（Collin）让林克到村里看看有什么可以帮助大家的，也让艾普娜休息一天，看来将会是忙碌的一天啊。刚进村就有村民要林克帮忙除掉屋后大树顶上的马蜂窝，林克当然爽快答应，没走两步看到汉奇（Hanch）站在一处高台上，和他对话（按Z然后按A），练习攀登（接近树藤按前，上下左右移动）。林克攀爬上去，汉奇让林克试着吹响灌木召唤隼鹰并且告诉林克他们家的猫咪老是在湖边打转不肯回家。林克跳到（对准方向按前就可以了）旁边的高台上，用灌木吹起了口哨，一只隼鹰飞到了林克的手臂上，此时可以命令隼鹰飞到指定的地方。首先帮村民搞定马蜂窝吧，让隼鹰撞落村里最高树上的马蜂窝，爬到树上在原来挂马蜂窝的地方可以拣到15个卢比。在湖边看到了柯林的妈妈正在犯愁，原来是前段时间不小心将婴儿摇篮掉到河中被水冲走了，林克当然不能坐视不管，顺着河往下游游去，看到水中一个巨石上有只猴子举着婴儿摇篮，林克爬到岸上，举起石头向猴子砸去，但是仿佛距离不够，看来只有暂时先返回村子了。回到村里林克想起了汉奇的话，看来可以让隼鹰帮忙把婴儿摇篮抓回来，爬上汉奇站的高台，从旁边的高台跳到屋顶上，然后再跳到另一个高台上，隐约可以看到远处的猴子，召唤隼鹰瞄准猴子，隼鹰果然漂亮地将婴儿摇篮给夺了回来。带着婴儿摇篮回到柯林妈妈那里，她高兴万分，让林克跟她一起回家，因为有神秘的礼物要送给林克。来到她家门口，原来是一副钓鱼竿，有了钓鱼竿，林克可以到湖边去放松一下了，来到刚才看到的有小猫的湖边钓鱼。按-号调出道具栏，将钓竿装备到B（装备到右手手柄的左右下也可以，使用前会道具切换到B），在河边按B使用钓竿，按B把鱼竿甩进水里，然后等待，当浮标被拉下水后，把右手的Wii手柄举高，出现HIT，继续保持举高的姿势，直到钓上鱼。林克钓上来的第一条鱼就引起了小猫的注意，刚钓上第二条时，小猫叼着鱼就开跑，一路跑回了家，林克追了过去，店主塞拉（Sera）为了感谢林克，送给林克一瓶牛奶，牛奶可以让林克感到体力充沛，不过这个瓶子将来更有其他的用处。出门来到农场山脚下的村长布（Bo）的家门口，正在与布谈话时，听到农场主的喊声，回头望去，原来是山羊跑出了农场，朝山坡下冲了过来，林克凭借着敏捷的反应，顺手抓住山羊的角，然后将其摔翻在地上，山羊就乖乖地返回牧场。村里最高的房顶上可以拣到10个卢比，看到牧场方向的平台上还有10个，这时召唤隼鹰，让隼鹰把附近的鸡给带上来，然后可以借助鸡滑翔到对面的平台上。这时拣到的卢比也超过了30个了，可以去商店买弹弓了。商店有弹弓，蜜蜂幼虫（B装备钓竿的情况下，使用蜜蜂幼虫，可以拿去钓鱼，需要空瓶子装）和回复药（需要空瓶子装）出售。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_03.jpg"><div id="attachment_1061" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_03-700x466.jpg" alt="tp_ch01_03" title="tp_ch01_03" width="700" height="466" class="size-large wp-image-1061 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">林克凭借着敏捷的反应，顺手抓住山羊的角，然后将其摔翻在地上</p></div></a></p>
<h5>陪孩子们玩</h5>
<p>做了那么多的事情，林克也累了，回家休息一下吧，在家门口遇到了鲁斯尔，鲁斯尔告诉林克在他家中放了一个箱子。林克迫不及待地想回去看看究竟是什么东西，可没走两步又被家门口的3个小孩马洛（Malo）、塔洛（Talo）、贝思（Beth）吵着要林克表演弹弓技术，帅气的林克当然会满足他们的愿望，和装备钓竿的方法一样装备弹弓，使用弹弓后按住B拉开弹弓，用右手的Wii手柄瞄准目标，放开B射击，按Z可以锁定近处的目标。分别打完靶子和稻草人后，小孩们被林克高超的技艺所折服。终于可以回家了，房子前的藤条上居然出现了魔蜘蛛，用弹弓将其击落。一进门就看到了鲁斯尔给林克的箱子，赶紧打开看看，一把木剑!林克终于有武器了。林克激动得出门想练练剑，刚好小孩们又吵着要林克表演剑术，不过好像他们产生了分歧，贝思很喜欢林克的表演，马洛却觉得林克不过是表演些雕虫小技。按他们的请求耍出剑招：</p>
<ol>
<li><strong>平挥：</strong>把wiimote从一边甩到另一边（左右挥动）；</li>
<li><strong>直斩：</strong>从上往下甩wiimote；</li>
<li><strong>直刺：</strong>按住Z和前（前倾nunchunk的模拟摇杆），挥动wiimote；</li>
<li><strong>旋转攻击：</strong>左右挥动nunchunk；</li>
<li><strong>跳斩：</strong>用Z键锁定后按A。</li>
</ol>
<p>在林克一阵刀光剑影之后，小孩们都惊呆了，贝思更是对林克赞不绝口。这时那只拣走婴儿摇篮的猴子又出现了，引起小孩们的好奇，塔洛追着猴子进了法隆森林。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_04.jpg"><div id="attachment_1063" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_04-700x466.jpg" alt="tp_ch01_04" title="tp_ch01_04" width="700" height="466" class="size-large wp-image-1063 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">林克表演剑术</p></div></a></p>
<h4>法隆森林</h4>
<h5>救出被捉的孩子</h5>
<p>跟过去发现塔洛跟随猴子到吊桥对面去了，回去骑上心爱的艾普娜，林克也追进了法隆森林，穿过法隆森林泉左边的山洞，来到一个岔路口，看来跟丢了，往左边走，看到一个了隐居商人柯洛（Coro），他送给林克一盏煤油灯，用100块买油瓶子（重点是装油的瓶子，只能买一次）。回到岔路口，林克用煤油灯烧开蜘蛛网，进入山洞，洞中有很多台柱是可以用灯点燃的，有煤油灯的帮助，林克穿过漆黑的山洞，来到一处开阔地，林克在北面的洞口干掉几个小喽啰，路上有两根柱子，看起来可以跳过去，但实际上并不能，人类还是没法做到的。进入洞中，在最深处的宝箱里面得到一把钥匙，林克又点燃箱子左右的灯柱，出现了一个隐藏宝箱，可以得到<a href="http://www.gocalf.com/blog/zelda-tp-heartpiece.html#H01">第一块心之碎片</a>，每收集满5个心之碎片，林克的生命值可以增加一颗心，即一个心之容器。然后回到之前的那片开阔地，到东面干掉两个守卫后用刚得到的钥匙开门进去，不远出碰到一只小鹦鹉，此处可以补充生命值和灯油，不过就算是救世主的林克来光顾也不是免费的，旁边还有一个箱子就是让顾客消费后自己投币的，如果林克购买了物品而不老实买单的话，鹦鹉可不会放林克离开的。继续前进，林克一路杀进去，没多远就看到了关押小猴子和塔洛的笼子，轻松干掉两个守卫后，林克砍坏笼子救出了小猴子和塔洛，塔洛告诉林克，要不是小猴子一直骚扰魔物，他可能都被杀害了，正是因此小猴子也被魔物抓住关到了笼子里。林克带着塔洛回到了村里，自己也回家休息了。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_05.jpg"><div id="attachment_1064" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_05-700x466.jpg" alt="tp_ch01_05" title="tp_ch01_05" width="700" height="466" class="size-large wp-image-1064 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">关押小猴子和塔洛被关押在笼子中</p></div></a></p>
<p>一大早农场主又要拜托林克赶羊，不过这次是要在3分钟之内赶完20只，完成后，林克在农场的山脚下遇到了伊莉娅，伊莉娅看到艾普娜的脚受伤了，便生气地带着艾普娜离去了，林克只好独自回家。路上遇到柯林要林克带他去奥东之泉看艾普娜，之后又遇到了那三个调皮的小孩拦路要林克把木剑给他们玩，不答应他们的话是过不去的，看来没办法了只好暂时借他们玩玩。来到奥东之泉，伊莉娅却紧闭大门不让林克进去，看来她还在生气，柯林告诉林克有个地方的小洞可以通往奥东之泉里面。回到路上有松鼠的地方，林克找到小洞钻了过去。林克答应伊莉娅会好好照顾艾普娜，伊莉娅也才同意将艾普娜交给林克，正在此时，一群凶悍的野猪骑士破门而入，将林克打昏在地，并带走了伊莉娅和柯林。醒来后的林克感觉到了事情的严重，于是急忙朝法隆森林深处追了过去，穿过吊桥，发现一堵黑暗之墙挡住了去路，林克感觉到了不寻常的力量，刚想靠近黑暗之墙调查一番，却被一只巨大的手抓入了黑暗世界。来到黑暗世界中的林克被一种强大的力量变成了狼的形态，涉世未深的林克承受不住这股强大的力量，便昏迷了过去……</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_06.jpg"><div id="attachment_1065" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_06-700x466.jpg" alt="tp_ch01_06" title="tp_ch01_06" width="700" height="466" class="size-large wp-image-1065 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">一群凶悍的野猪骑士破门而入，将林克打昏在地，并带走了伊莉娅和柯林</p></div></a></p>
<h4>海拉尔城堡</h4>
<h5>脱出黄昏世界</h5>
<p>林克从昏迷中醒来后惊奇得发现自己变成了狼的形态，而起被锁在一间牢房里。此时一个神秘的独眼生物出现，林克下意识得提高了警觉，不过它却帮林克解开了锁链，暂时看来它不是敌人，它说要想逃出这个地方就得听它的话，对准牢笼边的木箱挥动右手手柄或者按住Z按A，将其击碎，然后在松软的泥土处按右手手柄的下，挖洞离开牢笼。神秘生物毫不客气得骑到了林克背上，救世主被人骑的滋味一定很不爽，但是为了逃出这个地方只有暂时忍气吞声了。神秘生物的头部可以长出一只手打开一些吊环机关（按住Z按A），看来它的来头不小啊，林克发现这个黑暗世界与光明世界是相通的，光明世界里的人们在黑暗世界中看来便是灵魂，通过狼的感知（按右手手柄的左或者右进入感应模式，感应模式下视觉会缩小，但能看见很多平时看不见的东西），林克可以听到他们的谈话。继续探索下水道，有很多机关和钱在等着你。小心这里的敌人并不好对付，掉下水的话尽快上岸，如果在水中被攻击的话是很惨的。在几个拉索机关后，进入一座桥的废墟，小心头上飞来飞去的怪鸟，最好杀死它们后再前进，灵活利用Z锁定然后攻击，很容易杀死它们。跟着神秘生物的提示，林克一直来到一个螺旋楼梯的高塔处，这里它会带林克飞过一些断口的地方，一路上到顶部，通过门来到城堡外部，神秘生物带着林克经过房顶来到一座塔内。在塔顶林克见到了一位黑衣人，难道自己被神秘生物欺骗了?这也许就是幕后指使者，正当林克猜测时，黑衣人转过身来，原来她就是伟大的<a href="http://www.gocalf.com/blog/zelda-tp-characters.html#Zelda">塞尔达（Zelda）公主</a>。从塞尔达公主口中得知神秘生物叫做<a href="http://www.gocalf.com/blog/zelda-tp-characters.html#Midna">米德娜（Midna）</a>，原来这一切都是一个叫做<a href="http://www.gocalf.com/blog/zelda-tp-characters.html#Zant">赞特（Zant）</a>的魔法师所策划的整个阴谋，塞尔达公主为了子民不受到迫害，而被囚禁在这里，塞尔达公主告诉林克赶快离开这里，以免被赞特的手下发现，林克只好逃出塔外，在屋顶米德娜发动魔法将林克传送回光明世界。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_07.jpg"><div id="attachment_1066" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_07-700x466.jpg" alt="tp_ch01_07" title="tp_ch01_07" width="700" height="466" class="size-large wp-image-1066 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">变成狼形态的林克与米德娜</p></div></a></p>
<h4>奥东村</h4>
<h5>寻找剑与盾</h5>
<p>林克发现自己被传送到了奥东之泉，但是回到光明世界的林克仍然是狼的形态，米德娜要林克搞到一面盾和一把剑，为变成人的时候做准备。回到家门口林克发现在狼的形态下可以听懂动物的语言。来到村中水车处，林克偷听到了两位村民的对话，得知小孩们被魔物俘走了，但林克忘了自己是处于狼的形态，正想上前听得再清晰一些，结果被村民发现，两人以为是魔物来了，匆忙逃进屋内。林克没有办法开门进去，看来只好走房顶的窗口进去了，但是水车旁边的高台上有村民带着隼鹰守夜，林克只好先跳到商店屋顶再从背后吓走高台上的村民，然后通过水车跳到对面的房顶上，从窗口进去。进去后发现墙上有面盾牌，撞下取得后从旁边的窗口离开。谁有武器呢？林克想了想，导师鲁斯尔那一定有把，前往鲁斯尔的家，但是就算是导师也认不出林克了，挥舞着剑不停的驱赶眼前的这只野兽，看来只有从旁边绕过去了，进入感应模式，能看见地上有些地方一闪一闪的，代表这些地方是可以挖的，在靠屋子的闪光处挖，进去拿到剑后赶紧离开吧，因为现在大家都不欢迎林克。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_08.jpg"><div id="attachment_1067" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_08-700x466.jpg" alt="tp_ch01_08" title="tp_ch01_08" width="700" height="466" class="size-large wp-image-1067 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">在导师鲁斯尔家里找到剑</p></div></a></p>
<h4>法隆地区</h4>
<h5>第一位光之精灵</h5>
<p>带着剑和盾，林克一心只想救出塞尔达公主，一路狂奔，经过奥东之泉时却遇到了<a href="http://www.gocalf.com/blog/zelda-tp-characters.html#ShadowBeing">暗影使者（Shadow Being）</a>，林克轻松将其击倒，消灭暗影使者后，光之精灵奥多那（Ordona）出现，告诉林克世界上一共有四位光之精灵，要想让世界恢复正常，必须要依靠四位光之精灵的力量，奥多那让林克去找到另外三位光之精灵。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_09.jpg"><div id="attachment_1069" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_09-700x466.jpg" alt="tp_ch01_09" title="tp_ch01_09" width="700" height="466" class="size-large wp-image-1069 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">要想让世界恢复正常，必须要依靠四位光之精灵的力量</p></div></a></p>
<h5>第二位光之精灵</h5>
<p>世界正在被黑暗吞噬，刻不容缓，林克和米德娜来到黑暗之墙外，米德娜问林克是否做好了进入黑暗世界的准备，这根本没有思考的余地，林克坚定的点了点头。刚一进入黑暗世界便遇到三只黑暗使者，当它们死剩一只时，会全体复活。米德娜告诉林克，要同时击倒三个暗影使者才能将他们彻底消灭，米德娜会教林克发动群体攻击技能。按住B键会产生一个攻击范围，放开，范围内的敌人会全部被杀死，但一次杀三只，难度比较大，建议杀剩下两只的时候，再使用范围攻击。</p>
<p>解决后第二位光之精灵出现，它交给林克光之容器（Vessel of Light），让林克去收集光之泪（Tears of Light）。</p>
<h5>收集光之泪</h5>
<p>林克根据地图上的白色标记，利用感知发现并消灭掉那些虫子后便可收集到光之泪，因为找到它们难度并不大，所以这里不具体说明。提示：</p>
<ol>
<li>开感应模式才能看见影子虫；</li>
<li>影子虫是有些在屋子里的，找不到的话进附近的屋子找；</li>
<li>有些要和附近的鬼魂对话才会出现；</li>
<li>有突然出现潜入地底的情况，挖地或者等待会出现；</li>
<li>森林的中心位置会有毒雾（瘴气），林克没有办法前进，只有借助米德娜的传送才能通过，如果是晚上的话中途会看见幽灵的灯，进感应模式，将它杀死可以获得<a href="http://www.gocalf.com/blog/zelda-tp-ghostsoul.html">鬼魂之魂</a>；</li>
<li>杀完虫子别忙着走，要记得拿光之泪。</li>
</ol>
<p>收集完所有的光之泪后法隆地区（Faron Province）的黑暗褪去，森林被净化了，光之精灵法隆（Faron）恢复了原形，没有了黑暗力量的压迫，林克也变回了人形，身上换成了系列经典的绿色套装，法隆告诉林克，他是被光之神选中的英雄，林克再次肩负起拯救世界的重任。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_10.jpg"><div id="attachment_1070" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_10-700x466.jpg" alt="tp_ch01_10" title="tp_ch01_10" width="700" height="466" class="size-large wp-image-1070 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">光之精灵</p></div></a></p>
<h5>前往森之神殿</h5>
<p>之后林克来到柯洛处，柯洛会给林克一把钥匙，用来打开岔路处的锁，穿过山洞来到瘴气覆盖的地方。没有了米德娜的帮忙，林克只好拿出灯来趋散瘴气，不过猴子却出现并抢走了林克的灯，林克气愤得以为猴子在这种时候还来捣乱，不过猴子其实是来帮助林克引路的，看来误会它了。跟着小猴子穿过瘴气，林克一路向前，突然看见有一只金色的狼蹲坐在路中间，林克走过去，狼却扑了过来，一阵眩晕之后，林克发现自己在一个陌生的空间中，看到眼前站着一位不死勇士（Undead Warrior），林克正在困惑之时，不死勇士开口了，原来他是专门守候在这里给救世主传授绝技，他会教给林克终结刺（Ending Blow），学会后林克返回到现实当中，眼前就是森之神殿（Forest Temple）的入口。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_11.jpg"><div id="attachment_1071" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_11-700x466.jpg" alt="tp_ch01_11" title="tp_ch01_11" width="700" height="466" class="size-large wp-image-1071 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">用灯来趋散瘴气</p></div></a></p>
<h4>森之神殿迷宫</h4>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_12.jpg"><div id="attachment_1072" class="wp-caption alignnone" style="width: 523px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_12-513x700.jpg" alt="tp_ch01_12" title="tp_ch01_12" width="513" height="700" class="size-large wp-image-1072 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">森之神殿迷宫地图</p></div></a></p>
<p><strong>房间1：</strong>林克刚进入森之神殿。左边的蔓腾上去有宝箱。走了不远，又看到不走运的猴子被关在笼子里，再次将其救出。之后射死蜘蛛爬上藤条进入房间2。</p>
<p><strong>房间2：</strong>这里林克会遇到蜘蛛炸弹，用它可以帮助炸开一些腐坏的门以及挡路的石头。当炸弹蜘蛛试图接近你，你用你的盾的阻止他们攻击你的话，他们会后退然后最终爆炸。在它们作出这些行动之前，你可以抓住他们。抓住一只扔向房间北面的大的岩石墙上，靠近他们洞穴的地方，你将会得到装着20卢比的箱子。到中间的高台上，你将会面对一个大的蜘蛛，这些家伙将会防御你的攻击，但如果你只是简单的按着按钮Z，然后等他们暴跳，然后相互殴打。你将不费吹灰之力消灭他们。点燃灯柱，前面升降梯会升起形成一条路，然后进入对面到房间3。</p>
<p><strong>房间3：</strong>林克正要过桥的时候桥会被打断，只得原路返回到房间2。回到中间高台处，向西面走，刚才救的猴子会会荡秋千，帮你前往西面的高台。按前跳跃捉住猴子后，出现A指令按A放手就可以到对面进入到房间4。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_13.jpg"><div id="attachment_1073" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_13-700x466.jpg" alt="tp_ch01_13" title="tp_ch01_13" width="700" height="466" class="size-large wp-image-1073 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">林克正要过桥的时候，桥被打断了</p></div></a></p>
<p><strong>房间4：</strong>先去右边利用蜘蛛炸弹将石头炸掉后，可以得到欧库（Ooccoo），是一个流落人间的天空人，她能帮助林克逃离迷宫并且再回到离开处（在迷宫中使用母亲，会被传送出迷宫，在迷宫外使用儿子会回到使用母亲的地方，十分之方便），之后向北进入房间3的左边吊桥，通过后到对面的房间5取得一把小钥匙（Small Key），之后再回到房间4。打开西面的门进入房间6。</p>
<p><strong>房间6：</strong>下面的柱子上有一只被关住的猴子，（用前加A）撞柱子的话可以将笼子撞下来打碎，救出猴子后，带着两只猴子回到中间的房间2。</p>
<p><strong>房间2：</strong>在两只猴子的帮助下可以向西面到房间7。</p>
<p><strong>房间7：</strong>这个房间有2个霸王花，普通攻击无法将其消灭，可以从2楼拿蜘蛛炸弹扔下来消灭掉它们，南面的那个后面的箱子里有<a href="http://www.gocalf.com/blog/zelda-tp-heartpiece.html#H02">心之碎片</a>。之后再用2楼的蜘蛛炸弹炸开东面挡路石头（拿着跳过去扔），之后可以进入房间8。</p>
<p><strong>房间8：</strong>进入后可以在台子上看到下面两个柱子，其中左边的柱子上有个箱子，像之前救第2只猴子那样将其撞下可以得到小钥匙。从水里游过去上岸后点燃左右的两个灯柱后会有梯子升起，这样就可以爬上去救出第3只猴子了。回到房间7，然后向南边走进入房间9。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_14.jpg"><div id="attachment_1074" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_14-700x466.jpg" alt="tp_ch01_14" title="tp_ch01_14" width="700" height="466" class="size-large wp-image-1074 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">点燃左右的两个灯柱后会有梯子升起</p></div></a></p>
<p><strong>房间9：</strong>这里会遇到一个食人花和霸王花的合成体，要先砍掉它的脑袋，然后将蜘蛛炸弹扔入肚子消灭后可以取回被他吞下的钥匙，之后可以救回第4只猴子。</p>
<p><strong>房间3：</strong>带着4只猴子到房间3通过之前断开的吊桥来到房间10见到了小BOSS——被影子虫依附的猴子王。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_15.jpg"><div id="attachment_1075" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_15-700x466.jpg" alt="tp_ch01_15" title="tp_ch01_15" width="700" height="466" class="size-large wp-image-1075 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">在4只猴子的帮助下通过之前断开的吊桥</p></div></a></p>
<p><strong>房间10：</strong>此战比较简单，看到BOSS扔出回旋镖后迅速撞击他所站的柱子，BOSS会因为站不稳而没接到回旋镖并被回旋镖打下，此时攻击它的屁股，反复几次后战胜并取得道具回旋镖（Gale Boomerang），之后朝进来的门上面的机关使用回旋镖可以回到房间3。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_16.jpg"><div id="attachment_1076" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_16-700x466.jpg" alt="tp_ch01_16" title="tp_ch01_16" width="700" height="466" class="size-large wp-image-1076 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">当小BOSS没接到回旋镖并被回旋镖打下后，赶紧过去攻击它的屁股</p></div></a></p>
<p><strong>房间3：</strong>现在可以控制这里桥的转向（利用回旋镖吹动桥上的风叶），先去右边救被困的猴子（用回旋镖将绳子打断即可）。此后可以回到之前救第三只猴子的地方将灯熄灭，降下最里面的梯子后得到<a href="http://www.gocalf.com/blog/zelda-tp-heartpiece.html#H03">心之碎片</a>。</p>
<p><strong>房间2：</strong>回到房间2，用回旋镖将天花板上挂着的东西悉数击落，其中的宝箱里有道具指南针，利用他可以观察迷宫中宝箱、Boss和猴子的位置。从吊桥房间左边的吊桥过去到房间4。</p>
<p><strong>房间4：</strong>按照地上标记指示的顺序将风车图腾激活可以取得大钥匙（Big Key）。然后对直走进入房间5，再朝东进入房间13。</p>
<p><strong>房间13：</strong>救下上层的猴子后回到房间5，走北面的门进入房间11。</p>
<p><strong>房间11：</strong>之前被救的猴子都在这里，首先利用回旋镖为动力转动东面的吊桥以到达最东面的门进入房间12。</p>
<p><strong>房间12：</strong>在房间的最南面的箱子里有一把小钥匙，而最东面的路被挡住了，利用回旋镖从北面水中的石头上取来蜘蛛炸弹，记得先锁定蜘蛛炸弹再将第2目标锁到石头上可以炸开，上去后能救到猴子。拿着刚取得的小钥匙回到房间5并走西面打开门进入房间14。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_17.jpg"><div id="attachment_1077" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_17-700x466.jpg" alt="tp_ch01_17" title="tp_ch01_17" width="700" height="466" class="size-large wp-image-1077 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">房间12中要救的小猴子</p></div></a></p>
<p><strong>房间14：</strong>注意地板下面的怪，可以用回旋镖将其卷出来，救到最后一只猴子后去房间11，他们会帮林克通过中间的大断崖到对面进入Boss房间15。Boss房间前精灵标志的地方，打烂罐子会出现精灵，记得用瓶子装，带在身上，可以自动复活一次。</p>
<p><strong>BOSS站：</strong>食人花——达巴巴（Twilit Parasite——Diababa）</p>
<p>进入房间，首先出现的是两个超级巨型食人花，利用其下两个台子上的蜘蛛炸弹再配合回旋镖可以将炸弹送到食人花的嘴巴里，很快就能将之干掉，但是战斗并没有结束，随后食人花的头部出现，这时之前的台子会被达巴巴的躯体挡住，但是不一会儿，之前的战胜的那只大猴子会出现并为林克提供炸弹蜘蛛，有了这个随后就可以轻松获胜了。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_18.jpg"><div id="attachment_1078" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_18-700x466.jpg" alt="tp_ch01_18" title="tp_ch01_18" width="700" height="466" class="size-large wp-image-1078 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">BOSS：食人花——达巴巴（Twilit Parasite——Diababa）</p></div></a></p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_19.jpg"><div id="attachment_1079" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/tp_ch01_19-700x466.jpg" alt="tp_ch01_19" title="tp_ch01_19" width="700" height="466" class="size-large wp-image-1079 wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">用回旋镖将蜘蛛炸弹送到食人花的嘴巴里</p></div></a></p>
<hr />
<p>参考：</p>
<ul style="padding-right: 40px; ">
<li><a href="http://wii.tgbus.com/glmj/gl/200611/20061129114849.shtml" target="_blank">《塞尔达传说：黄昏公主》图文全攻略</a>&nbsp;by WiiBbs 攻研部 Szh、三代鬼彻、天堂的翅膀</li>
<li><a href="http://www.cngba.com/thread-16520313-1-1.html" target="_blank">《塞尔达传说 黄昏公主》完美攻略研究</a> by www.cngba.com 鸡蛋</li>
<li><a href="http://tv.duowan.com/0710/57154029137.html" target="_blank">Wii《塞尔达传说：黎明公主》流程攻略</a></li>
</ul>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/zelda-tp-characters.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：角色介绍'>《塞尔达传说：黎明公主》攻略：角色介绍</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-intro.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：剧情介绍'>《塞尔达传说：黎明公主》攻略：剧情介绍</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch2.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：第二章 死亡山颠的咆哮'>《塞尔达传说：黎明公主》攻略：第二章 死亡山颠的咆哮</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch3.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：第三章 深海鱼族的传说'>《塞尔达传说：黎明公主》攻略：第三章 深海鱼族的传说</a></li>
<li><a href='http://www.gocalf.com/blog/check-udisk.html' rel='bookmark' title='U盘检测软件：ChipGenius，MyDiskTest'>U盘检测软件：ChipGenius，MyDiskTest</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/zelda-tp-ch1.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[《塞尔达传说：黎明公主》攻略]]></series:name>
	</item>
		<item>
		<title>U盘检测软件：ChipGenius，MyDiskTest</title>
		<link>http://www.gocalf.com/blog/check-udisk.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=check-udisk</link>
		<comments>http://www.gocalf.com/blog/check-udisk.html#comments</comments>
		<pubDate>Thu, 08 Sep 2011 14:13:36 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[硬件]]></category>
		<category><![CDATA[ChipGenius]]></category>
		<category><![CDATA[Disk Check]]></category>
		<category><![CDATA[FlashDisk]]></category>
		<category><![CDATA[MyDiskTest]]></category>
		<category><![CDATA[U盘检测]]></category>
		<category><![CDATA[优盘检测]]></category>
		<category><![CDATA[移动存储]]></category>
		<category><![CDATA[金士顿U盘]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=1019</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/usbdrive.png" class="attachment-post-thumbnail wp-post-image" alt="usbdrive" title="usbdrive" /></div>以前买到过一个假冒的8GB U盘，是用劣质的4GB芯片改装的，后来用软件检测出来了，今天来分享一下。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/usbdrive.png" class="attachment-post-thumbnail wp-post-image" alt="usbdrive" title="usbdrive" /></div><p>几年前的事情了。有一次去北邮玩，看到校园里有卖U盘的摊位，问了问价格，8GB的金士顿U盘99块钱。正好头一天有个同事跟我说最近U盘降价了，8GB才99，于是心里一痒痒就买了一个。回来用着就感觉不对劲，读写速度超慢不说，放的东西多了之后就有好多读不出来。赶紧找了软件来检测，果然是假货，是用4GB的假冒机芯改装的。今天分享一下检测用的软件和方法。<span id="more-1019"></span></p>
<p>先介绍一下在没有软件的时候怎么判断是否是真的金士顿U盘。直观上可以仔细观察U盘上的标签、防伪标识、防伪电话等等，制作粗糙的一般都是假冒的。除此之外可以注意两点：</p>
<ul>
<li>当真的金士顿U盘接到电脑上后，电脑中显示的卷标应该是“Kingston”（刚买来的应该是这样），而假冒的一般会是“可移动磁盘”之类的；</li>
<li>真的金士顿U盘在读写的时候，背部的小灯会闪烁，但假冒的一般不会亮。</li>
</ul>
<p>下面介绍第一个小软件：ChipGenius。它可以识别出U盘（或其他USB设备）的主控芯片型号、制造商、品牌等信息。这个软件绿色小巧，便于携带，是外出选购U盘是必不可少的工具之一。下面两张图是真假金士顿U盘用此软件识别后的对比，真的U盘是公司发的，假的是我在北邮买的。</p>
<div id="attachment_1028" class="wp-caption alignnone" style="width: 572px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/real_kingston.png" alt="real_kingston" title="real_kingston" width="562" height="442" class="size-full wp-image-1028 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">正牌8G金士顿U盘在ChipGenius中的检测结果</p></div>
<p>&nbsp;</p>
<div id="attachment_1029" class="wp-caption alignnone" style="width: 572px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/fake_kingston.png" alt="fake_kingston" title="fake_kingston" width="562" height="441" class="size-full wp-image-1029 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">冒牌扩容8G金士顿U盘在ChipGenius中的检测结果</p></div>
<p>可见，关键的区别就在产品制造商（Product Vendor）和产品型号（Product Model）上，正牌的应该是Kingston DataTraveler 2.0，而假冒的通常都是USB 2.0 Flash Disk之类的东西。</p>
<p>有一点比较奇怪的是，我在英文Vista上运行该软件，显示版本是2.64，在中文Xp上运行，则显示2.70，呵呵，无视之。</p>
<p>如果只是芯片是冒牌货我也忍了，最可气的是芯片的实际容量只有4GB。接下来介绍的这个软件就可以检测出来，叫做MyDiskTest。这个软件功能很强，我最喜欢的就是扩容检测和坏块扫描了，速度很快，比我自己写的程序一点一点扫描快多了。另外它还可以进行速度测试和坏块屏蔽。不说废话，直接上对比图，还是我的一真一假两只U盘。</p>
<div id="attachment_1030" class="wp-caption alignnone" style="width: 323px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/real_8g_chip.png" alt="real_8g_chip" title="real_8g_chip" width="313" height="382" class="size-full wp-image-1030 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">正牌8G金士顿U盘在MyDiskTest中的检测结果</p></div>
<p>&nbsp;</p>
<div id="attachment_1031" class="wp-caption alignnone" style="width: 538px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/fake_8g_chip.png" alt="fake_8g_chip" title="fake_8g_chip" width="528" height="502" class="size-full wp-image-1031 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">冒牌扩容8G金士顿U盘在MyDiskTest中的检测结果</p></div>
<p>可见，我这个假冒的U盘是用杂牌的4G机芯改装出来的。由于是在校园里路边买的，虽然要了收据（号称是海龙的来这里搞活动），但收据上的摊位也是假的。目前只好暂时用MyDiskTest把坏块屏蔽掉使用了（否则写入的文件超过4G后的内容将无法写入但又不会报错，直到读出来的时候才会发现内容全部是0×00）。</p>
<p>好在两个软件都非常小，这里就直接提供下载吧（压缩包内有详细使用说明，就不多说了）：</p>
<ul>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/ChipGenius_264.zip">ChipGenius v2.64</a> （113K） MD5：2628f1748e558bd71ab661ae1ab27aa5</li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/09/MyDiskTest_250.zip">MyDiskTest v2.50</a> （610K） MD5：7d4bfeb1e01f748fe3bd2b6a590bd83b</li>
</ul>
<p>真想哪天背着本本出来去街边买个U盘，现场检测，揭穿这些奸商的把戏。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/zelda-tp-characters.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：角色介绍'>《塞尔达传说：黎明公主》攻略：角色介绍</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-2.html' rel='bookmark' title='2011.5.15我们的婚礼（二）——迎亲篇'>2011.5.15我们的婚礼（二）——迎亲篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-3.html' rel='bookmark' title='2011.5.15我们的婚礼（三）——准备篇'>2011.5.15我们的婚礼（三）——准备篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-1.html' rel='bookmark' title='2011.5.15我们的婚礼（一）——出发篇'>2011.5.15我们的婚礼（一）——出发篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-4.html' rel='bookmark' title='2011.5.15我们的婚礼（四）——仪式篇'>2011.5.15我们的婚礼（四）——仪式篇</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/check-udisk.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>单次遍历，等概率随机选取问题</title>
		<link>http://www.gocalf.com/blog/random-selection.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=random-selection</link>
		<comments>http://www.gocalf.com/blog/random-selection.html#comments</comments>
		<pubDate>Mon, 05 Sep 2011 16:24:48 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Coroutines and Generators]]></category>
		<category><![CDATA[Random Sample]]></category>
		<category><![CDATA[Random Selection]]></category>
		<category><![CDATA[单次遍历]]></category>
		<category><![CDATA[概率]]></category>
		<category><![CDATA[相等权重]]></category>
		<category><![CDATA[等概率]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[随机数]]></category>
		<category><![CDATA[随机选取]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=993</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/colorpicker.png" class="attachment-post-thumbnail wp-post-image" alt="colorpicker" title="colorpicker" /></div>又是一道概率问题，不过跟之前的题目一样，这也是一道非常简单的题目。 问题描述：假设我们有一堆数据（可能在一个链表里，也可能在文件里），数量未知。要求只遍历一次这些数据，随机选取其中的一个元素，任何一个元素被选到的概率相等。O(n)时间，O(1)辅助空间（n是数据总数，但事先不知道）。 如果元素总数为n，那么每个元素被选到的概率应该是1/n。然而n只有在遍历结束的时候才能知道，在遍历的过程中，n的值还不知道，可以利用乘法规则来逐渐凑出这个概率值。在《利用等概率Rand5产生等概率Rand3》中提到过，如果要通过有限步概率的加法和乘法运算，最终得到分子为1、分母为n的概率，那必须在某一次运算中引入一个n在分母上，而分母和分子上其他的因数则通过加法、乘法、约分等规则去除。 很容易能够想到这样一个简单的式子来凑出1/n： p_i=\frac{1}{i}\times\frac{i}{i+1}\times\frac{i+1}{i+2}\times\cdots\times\frac{n-1}{n}=\frac{1}{n} 下面用一段Python程序来实现这个过程，这里设计了一个类，叫做RandomSelector，提供方法AddItem，在遍历数据的时候把每个元素通过这个函数传进来，最后通过SelectedItem获取随机选择的元素。这么做主要是为了强调事先不知道元素的总数。 1234567891011121314151617181920from random import Random class RandomSelector: &#160; def __init__&#40;self, rand=None&#41;: &#160; &#160; self._selectedItem = None &#160; &#160; self._count = 0 &#160; &#160; self._rand = rand &#160; &#160; if self._rand is None: &#160; &#160; &#160; self._rand = Random&#40;&#41; &#160; def SelectedItem&#40;self&#41;: &#160; &#160; return self._selectedItem &#160; def Count&#40;self&#41;: &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/colorpicker.png" class="attachment-post-thumbnail wp-post-image" alt="colorpicker" title="colorpicker" /></div><p>又是一道概率问题，不过跟之前的题目一样，这也是一道非常简单的题目。</p>
<p>问题描述：假设我们有一堆数据（可能在一个链表里，也可能在文件里），数量未知。要求只遍历一次这些数据，随机选取其中的一个元素，任何一个元素被选到的概率相等。O(n)时间，O(1)辅助空间（n是数据总数，但事先不知道）。<span id="more-993"></span></p>
<p>如果元素总数为n，那么每个元素被选到的概率应该是1/n。然而n只有在遍历结束的时候才能知道，在遍历的过程中，n的值还不知道，可以利用乘法规则来逐渐凑出这个概率值。在<a href="http://www.gocalf.com/blog/build-rank3-from-rand5.html">《利用等概率Rand5产生等概率Rand3》</a>中提到过，如果要通过有限步概率的加法和乘法运算，最终得到分子为1、分母为n的概率，那必须在某一次运算中引入一个n在分母上，而分母和分子上其他的因数则通过加法、乘法、约分等规则去除。</p>
<p>很容易能够想到这样一个简单的式子来凑出1/n：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_2b8bb8674efdbc684b205c31760091ce.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p_i=\frac{1}{i}\times\frac{i}{i+1}\times\frac{i+1}{i+2}\times\cdots\times\frac{n-1}{n}=\frac{1}{n}" title="p_i=\frac{1}{i}\times\frac{i}{i+1}\times\frac{i+1}{i+2}\times\cdots\times\frac{n-1}{n}=\frac{1}{n}" /></span><script type='math/tex'>p_i=\frac{1}{i}\times\frac{i}{i+1}\times\frac{i+1}{i+2}\times\cdots\times\frac{n-1}{n}=\frac{1}{n}</script></p>
<p>下面用一段Python程序来实现这个过程，这里设计了一个类，叫做RandomSelector，提供方法AddItem，在遍历数据的时候把每个元素通过这个函数传进来，最后通过SelectedItem获取随机选择的元素。这么做主要是为了强调事先不知道元素的总数。</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">random</span> <span style="color: #ff7700;font-weight:bold;">import</span> Random<br />
<br />
<span style="color: #ff7700;font-weight:bold;">class</span> RandomSelector:<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> rand<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #008000;">self</span>._selectedItem <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><br />
&nbsp; &nbsp; <span style="color: #008000;">self</span>._count <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span><br />
&nbsp; &nbsp; <span style="color: #008000;">self</span>._rand <span style="color: #66cc66;">=</span> rand<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>._rand <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>._rand <span style="color: #66cc66;">=</span> Random<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> SelectedItem<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._selectedItem<br />
<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> Count<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._count<br />
<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> AddItem<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> item<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>._rand.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">self</span>._count<span style="color: black;">&#41;</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>._selectedItem <span style="color: #66cc66;">=</span> item<br />
&nbsp; &nbsp; <span style="color: #008000;">self</span>._count +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span></div></td></tr></tbody></table></div></pre>
<p>在Python 2.5中，yield不仅是个语句，更是一个表达式（详见<a href="http://www.python.org/dev/peps/pep-0342/" target="_blank">PEP 342 -- Coroutines via Enhanced Generators</a>，查阅Generator和Coroutine，中文叫做“生成器”和“协程”），利用yield可以把程序写的更简洁一些：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">random</span> <span style="color: #ff7700;font-weight:bold;">import</span> Random<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> RandomSelect<span style="color: black;">&#40;</span>rand<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:<br />
&nbsp; selection <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><br />
&nbsp; count <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> rand <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; rand <span style="color: #66cc66;">=</span> Random<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Outputs the current selection and gets next item</span><br />
&nbsp; &nbsp; item <span style="color: #66cc66;">=</span> <span style="color: #ff7700;font-weight:bold;">yield</span> selection<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> rand.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> count<span style="color: black;">&#41;</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span>:<br />
&nbsp; &nbsp; &nbsp; selection <span style="color: #66cc66;">=</span> item<br />
&nbsp; &nbsp; count +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span></div></td></tr></tbody></table></div></pre>
<p>下面这段程序示意了如何调用RandomSelect函数来测验其随机效果：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;"># Sample code to use RandomSelect function</span><br />
n <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">10</span><br />
repeat <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">100000</span><br />
occurrences <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
rand <span style="color: #66cc66;">=</span> Random<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>repeat<span style="color: black;">&#41;</span>:<br />
&nbsp; selector <span style="color: #66cc66;">=</span> RandomSelect<span style="color: black;">&#40;</span>rand<span style="color: black;">&#41;</span><br />
&nbsp; selector.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; selection <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> item <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; selection <span style="color: #66cc66;">=</span> selector.<span style="color: black;">send</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#41;</span><br />
&nbsp; occurrences<span style="color: black;">&#91;</span>selection<span style="color: black;">&#93;</span> +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
<span style="color: #ff7700;font-weight:bold;">print</span> occurrences</div></td></tr></tbody></table></div></pre>
<p>十个元素，重复十万次，理论上每个元素会被选中恰好一万次。某次实验结果如下：</p>
<pre><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[10020, 10084, 10003, 10008, 9985, 10145, 9987, 9925, 9955, 9888]</div></div></pre>
<p>可见每个元素被选中的次数相差不大，是等概率的。</p>
<p>如果用C#，就可以利用IEnumerable来实现，比如：</p>
<pre><div class="codecolorer-container csharp geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td><div class="csharp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">static</span> <span style="color: #6666cc; font-weight: bold;">bool</span> RandomSelect<span style="color: #008000;">&lt;</span>tsource<span style="color: #008000;">&gt;</span><span style="color: #008000;">&#40;</span><br />
&nbsp; &nbsp; IEnumerable<span style="color: #008000;">&lt;</span>tsource<span style="color: #008000;">&gt;</span> source,<br />
&nbsp; &nbsp; Random random,<br />
&nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">out</span> TSource selectedItem<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>source <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">throw</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> ArgumentNullException<span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;source&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>random <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; random <span style="color: #008000;">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> Random<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<br />
&nbsp; &nbsp; selectedItem <span style="color: #008000;">=</span> <span style="color: #0600FF; font-weight: bold;">default</span><span style="color: #008000;">&#40;</span>TSource<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span><br />
&nbsp; &nbsp; <span style="color: #6666cc; font-weight: bold;">int</span> count <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span><br />
&nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">foreach</span> <span style="color: #008000;">&#40;</span>TSource item <span style="color: #0600FF; font-weight: bold;">in</span> source<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>random<span style="color: #008000;">.</span><span style="color: #0000FF;">Next</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">++</span>count<span style="color: #008000;">&#41;</span> <span style="color: #008000;">==</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; selectedItem <span style="color: #008000;">=</span> item<span style="color: #008000;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #008000;">&#40;</span>count <span style="color: #008000;">&gt;</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div></tsource></tsource></pre>
<p>核心代码也就那么两三行而已，时间复杂度为O(n)（并且只遍历一次），空间复杂度为O(1)。其中Python的<code class="codecolorer python geshi"><span class="python"><span style="color: #dc143c;">random</span>.<span style="color: black;">randint</span><span style="color: black;">&#40;</span>x<span style="color: #66cc66;">,</span> y<span style="color: black;">&#41;</span></span></code>返回[x, y]之间的随机整数；C#的<code class="codecolorer csharp geshi"><span class="csharp">Random<span style="color: #008000;">.</span><span style="color: #0000FF;">Next</span><span style="color: #008000;">&#40;</span>x<span style="color: #008000;">&#41;</span></span></code>返回[0, x)之间的随机整数。</p>
<p>看一下概率，如果最终被选取的是第i个元素（1 <= i <= n），那就必须是遍历到它的时候，恰好被选中（<code class="codecolorer python geshi"><span class="python"><span style="color: #dc143c;">random</span>.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> i - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span></span></code>或者<code class="codecolorer csharp geshi"><span class="csharp">Random<span style="color: #008000;">.</span><span style="color: #0000FF;">Next</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">==</span> <span style="color: #FF0000;">0</span></span></code>），并且从此之后都恰好再也没有被其他元素替换掉。这些事件彼此独立，计算概率的方法正好是上面提到的式子，最终的概率就是1/n。</p>
<p>OK，问题解决了。结束之前再做个简单的扩展，改成等概率随机选取m个元素（可知每个元素被选中的概率都是m/n）。</p>
<p>解决办法也非常简单，只要在上面的代码中，把selectedItem（selection）改成一个长度为m的数组，稍作调整就可以了。</p>
<p>这里就给出Python的程序片段：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">random</span> <span style="color: #ff7700;font-weight:bold;">import</span> Random<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> RandomSample<span style="color: black;">&#40;</span>m<span style="color: #66cc66;">=</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> rand<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:<br />
&nbsp; selection <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; count <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> rand <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; rand <span style="color: #66cc66;">=</span> Random<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Outputs the current selection and gets next item</span><br />
&nbsp; &nbsp; item <span style="color: #66cc66;">=</span> <span style="color: #ff7700;font-weight:bold;">yield</span> selection<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>selection<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&lt;</span> m:<br />
&nbsp; &nbsp; &nbsp; selection.<span style="color: black;">append</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; idx <span style="color: #66cc66;">=</span> rand.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> count<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> idx <span style="color: #66cc66;">&lt;</span> m:<br />
&nbsp; &nbsp; &nbsp; &nbsp; selection<span style="color: black;">&#91;</span>idx<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> item<br />
&nbsp; &nbsp; count +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span></div></td></tr></tbody></table></div></pre>
<p>时间复杂度O(n)，空间复杂度O(m)（不可能是O(1)的）。概率的计算方法为：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_64966e159363007613acb79dbeb3a482.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p_i=\left\{\begin{array}{ll} \frac{m}{i}\times\frac{i}{i+1}\times\frac{i+1}{i+2}\times\cdots\times\frac{n-1}{n}=\frac{m}{n} & i > m \\ 1\times\frac{m}{m+1}\times\frac{m+1}{m+2}\times\cdots\times\frac{n-1}{n}=\frac{m}{n} & i \leq m \end{array} \right." title="p_i=\left\{\begin{array}{ll} \frac{m}{i}\times\frac{i}{i+1}\times\frac{i+1}{i+2}\times\cdots\times\frac{n-1}{n}=\frac{m}{n} & i > m \\ 1\times\frac{m}{m+1}\times\frac{m+1}{m+2}\times\cdots\times\frac{n-1}{n}=\frac{m}{n} & i \leq m \end{array} \right." /></span><script type='math/tex'>p_i=\left\{\begin{array}{ll} \frac{m}{i}\times\frac{i}{i+1}\times\frac{i+1}{i+2}\times\cdots\times\frac{n-1}{n}=\frac{m}{n} & i > m \\ 1\times\frac{m}{m+1}\times\frac{m+1}{m+2}\times\cdots\times\frac{n-1}{n}=\frac{m}{n} & i \leq m \end{array} \right.</script></p>
<p>等概率问题通常都是比较简单的。下一次将会对这个问题做进一步的扩展，变成每个元素都有一个权重，要求任何一个元素被选取的概率正比于其权重。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection-2.html' rel='bookmark' title='单次遍历，带权随机选取问题（二）'>单次遍历，带权随机选取问题（二）</a></li>
<li><a href='http://www.gocalf.com/blog/shuffle-algo.html' rel='bookmark' title='等概率随机排列数组（洗牌算法）'>等概率随机排列数组（洗牌算法）</a></li>
<li><a href='http://www.gocalf.com/blog/unbalcanced-coin.html' rel='bookmark' title='利用不均匀硬币产生等概率'>利用不均匀硬币产生等概率</a></li>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/random-selection.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>等概率随机排列数组（洗牌算法）</title>
		<link>http://www.gocalf.com/blog/shuffle-algo.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=shuffle-algo</link>
		<comments>http://www.gocalf.com/blog/shuffle-algo.html#comments</comments>
		<pubDate>Thu, 01 Sep 2011 13:58:37 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Shuffle]]></category>
		<category><![CDATA[排列问题]]></category>
		<category><![CDATA[概率]]></category>
		<category><![CDATA[洗牌算法]]></category>
		<category><![CDATA[等概率]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[随机数]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=980</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/cards_shuffle.png" class="attachment-post-thumbnail wp-post-image" alt="cards_shuffle" title="cards_shuffle" /></div>问题描述：假设有一个数组，包含n个元素。现在要重新排列这些数据，要求每个元素被放到任何一个位置的概率都相等（即1/n），并且直接在数组上重排（in place），不要生成新的数组。用 O(n) 时间、O(1) 辅助空间。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/09/cards_shuffle.png" class="attachment-post-thumbnail wp-post-image" alt="cards_shuffle" title="cards_shuffle" /></div><p>又是一道跟概率相关的简单问题。话说我的概率学的太差了，趁这个机会也从头开始补习一下。</p>
<p>问题描述：假设有一个数组，包含n个元素。现在要重新排列这些元素，要求每个元素被放到任何一个位置的概率都相等（即1/n），并且直接在数组上重排（in place），不要生成新的数组。用 O(n) 时间、O(1) 辅助空间。<span id="more-980"></span></p>
<p>算法是非常简单了，当然在给出算法的同时，我们也要证明概率满足题目要求。</p>
<p>先想想如果可以开辟另外一块长度为n的辅助空间时该怎么处理，显然只要对n个元素做n次（不放回的）随机抽取就可以了。先从n个元素中任选一个，放入新空间的第一个位置，然后再从剩下的n-1个元素中任选一个，放入第二个位置，依此类推。</p>
<p>按照同样的方法，但这次不开辟新的存储空间。第一次被选中的元素就要放入这个数组的第一个位置，但这个位置原来已经有别的（也可能就是这个）元素了，这时候只要把原来的元素跟被选中的元素互换一下就可以了。很容易就避免了辅助空间。</p>
<p>用Python来写一段简单的程序描述这个算法：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">random</span> <span style="color: #ff7700;font-weight:bold;">import</span> Random<br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> Shuffle<span style="color: black;">&#40;</span>li<span style="color: black;">&#41;</span>:<br />
&nbsp; rand <span style="color: #66cc66;">=</span> Random<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>li<span style="color: black;">&#41;</span> - <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> -<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>: &nbsp;<span style="color: #808080; font-style: italic;"># 逆序遍历li</span><br />
&nbsp; &nbsp; y <span style="color: #66cc66;">=</span> rand.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> x<span style="color: black;">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #808080; font-style: italic;"># 从剩余数据中随机选取一个</span><br />
&nbsp; &nbsp; li<span style="color: black;">&#91;</span>x<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> li<span style="color: black;">&#91;</span>y<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> li<span style="color: black;">&#91;</span>y<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> li<span style="color: black;">&#91;</span>x<span style="color: black;">&#93;</span> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># 将随机选取的元素与当前位置元素互换</span></div></td></tr></tbody></table></div></pre>
<p>主要的代码仅仅三行而已，浅显易懂。</p>
<p>来计算一下概率。如果某个元素被放入第i（<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_e0126ca144c4391269883a91304ade8d.gif' style='vertical-align: middle; border: none; ' class='tex' alt="1\leq i\leq n" title="1\leq i\leq n" /></span><script type='math/tex'>1\leq i\leq n</script>）个位置，就必须是在前 i - 1 次选取中都没有选到它，并且第 i 次选取是恰好选中它。其概率为：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_93e88f1552a22cb9e0813ddb813b0406.gif' style='vertical-align: middle; border: none; ' class='tex' alt="p_i=\frac{n-1}{n}\times\frac{n-2}{n-1}\times\cdots\times\frac{n-i+1}{n-i+2}\times\frac{1}{n-i+1}=\frac{1}{n}" title="p_i=\frac{n-1}{n}\times\frac{n-2}{n-1}\times\cdots\times\frac{n-i+1}{n-i+2}\times\frac{1}{n-i+1}=\frac{1}{n}" /></span><script type='math/tex'>p_i=\frac{n-1}{n}\times\frac{n-2}{n-1}\times\cdots\times\frac{n-i+1}{n-i+2}\times\frac{1}{n-i+1}=\frac{1}{n}</script></p>
<p>可见任何元素出现在任何位置的概率都是相等的。</p>
<p>实际上Python用户一定知道，在Random类中就有现成的shuffle方法，处理方法与我上面的程序是一样的。顺便也贴在这里学习一下。以下代码来自于 Python 2.5 Lib\random.py：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>250<br />251<br />252<br />253<br />254<br />255<br />256<br />257<br />258<br />259<br />260<br />261<br />262<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> shuffle<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> x<span style="color: #66cc66;">,</span> <span style="color: #dc143c;">random</span><span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">int</span><span style="color: #66cc66;">=</span><span style="color: #008000;">int</span><span style="color: black;">&#41;</span>:<br />
&nbsp; <span style="color: #483d8b;">&quot;&quot;&quot;x, random=random.random -&gt; shuffle list x in place; return None.<br />
<br />
&nbsp; Optional arg random is a 0-argument function returning a random<br />
&nbsp; float in [0.0, 1.0); by default, the standard random.random.<br />
&nbsp; &quot;&quot;&quot;</span><br />
<br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">random</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; <span style="color: #dc143c;">random</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">self</span>.<span style="color: #dc143c;">random</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">reversed</span><span style="color: black;">&#40;</span><span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># pick an element in x[:i+1] with which to exchange x[i]</span><br />
&nbsp; &nbsp; j <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">random</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> * <span style="color: black;">&#40;</span>i+<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; x<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> x<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> x<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> x<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span></div></td></tr></tbody></table></div></pre>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/random-selection.html' rel='bookmark' title='单次遍历，等概率随机选取问题'>单次遍历，等概率随机选取问题</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
<li><a href='http://www.gocalf.com/blog/unbalcanced-coin.html' rel='bookmark' title='利用不均匀硬币产生等概率'>利用不均匀硬币产生等概率</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection-2.html' rel='bookmark' title='单次遍历，带权随机选取问题（二）'>单次遍历，带权随机选取问题（二）</a></li>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/shuffle-algo.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>《塞尔达传说：黎明公主》攻略：角色介绍</title>
		<link>http://www.gocalf.com/blog/zelda-tp-characters.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=zelda-tp-characters</link>
		<comments>http://www.gocalf.com/blog/zelda-tp-characters.html#comments</comments>
		<pubDate>Tue, 30 Aug 2011 13:32:06 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[游戏]]></category>
		<category><![CDATA[Game]]></category>
		<category><![CDATA[Twilight Princess]]></category>
		<category><![CDATA[Wii]]></category>
		<category><![CDATA[任天堂]]></category>
		<category><![CDATA[塞尔达传说]]></category>
		<category><![CDATA[游戏攻略]]></category>
		<category><![CDATA[黄昏公主]]></category>
		<category><![CDATA[黎明公主]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=953</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_link_logo.jpg" class="attachment-post-thumbnail wp-post-image" alt="zelda_tp_link_logo" title="zelda_tp_link_logo" /></div>今天来介绍一下《塞尔达传说：黎明公主》中的几位角色，有好的也有敌人。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_link_logo.jpg" class="attachment-post-thumbnail wp-post-image" alt="zelda_tp_link_logo" title="zelda_tp_link_logo" /></div><p>《<a href="http://www.zelda.com/tp/" target="_blank">塞尔达传说：黎明公主</a>》（<a href="http://www.zelda.com/tp/" target="_blank">The Legend of Zelda: Twilight Princess</a>）是我玩的唯一的一个塞尔达传说系列的游戏，之前都没太关注过这个系列。开始的时候一直以为塞尔达（公主）是主角呢，后来发现是林克跟黎明公主。不知道这里面的塞尔达有什么特别的作用，感觉就是弱弱的呢。</p>
<p>今天来介绍一下《<a href="http://www.zelda.com/tp/" target="_blank">塞尔达传说：黎明公主</a>》中的几位角色，有好的也有敌人。<span id="more-953"></span></p>
<h3><a name="Link">主角：林克（Link）</a></h3>
<p>海拉尔大陆南端奥东村的年轻牧羊人，与村里的朋友们过着隐居的生活，并暗恋着村长的女儿伊莉娅，森林和自然赐予了他非凡的勇气和强健的体魄。作为女神所选择的勇士，林克肩负着拯救海拉尔世界的使命，平静的生活将在他进入法隆森林之时结束。</p>
<p>不过他为什么喜欢带“绿”帽子呢……话说我开始还以为塞尔达会是他的伴侣呢……</p>
<div id="attachment_961" class="wp-caption alignnone" style="width: 289px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_Link.jpg" alt="zelda_tp_Link" title="zelda_tp_Link" width="279" height="345" class="size-full wp-image-961 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">《塞尔达传说：黎明公主》主角：林克（Link）</p></div>
<h3><a name="Zelda">塞尔达（Zelda）</a></h3>
<p>善良温和的光之世界领主，拥有世代相传的光明力量。赞特统领的暗之军队入侵后，为了自己的子民能够保留性命，她不得不牺牲自身的自由，臣服于暗之世界，并被赞特软禁在海拉尔城堡顶层。唯一能做的，便是默默地祈祷着拯救世界的英雄出现。</p>
<p>“善良温和”，弱弱的样子，呵呵。</p>
<div id="attachment_963" class="wp-caption alignnone" style="width: 177px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_Zelda.jpg" alt="zelda_tp_Zelda" title="zelda_tp_Zelda" width="167" height="345" class="size-full wp-image-963 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">善良温和的光之世界领主：萨尔达（Zelda）</p></div>
<h3><a name="Midna">米德娜（Midna）</a></h3>
<p>谜一般怪异的人物，似乎拥有非常强大的魔力。为了寻找自己丢失在暗影世界中的神秘之物，米德娜需要借助林克强大的能力，在光与暗的世界中与他结伴而行，在与林克和塞尔达公主的相处中，她渐渐的表露出了自己善良的本性，和自己真实的身份……</p>
<p>话说游戏里她的声音挺有趣的呢，如果她一直没有变回去该多好啊。</p>
<div id="attachment_964" class="wp-caption alignnone" style="width: 185px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_Midna.jpg" alt="zelda_tp_Midna" title="zelda_tp_Midna" width="175" height="345" class="size-full wp-image-964 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">米德娜（Midna）</p></div>
<h3><a name="Ilia">伊莉娅（Ilia）</a></h3>
<p>与林克青梅竹马的乡村少女，拥有如森林中泉水般清澈的心灵。深爱自然与和平的她被兽人掠走后不幸地丢失了记忆，却在海拉尔大陆深处的隐蔽村落发现了通往天空之城的线索。为了她和她失去的记忆，林克走出了村庄，探寻起世界。</p>
<p>没什么戏份啊，是不是让我们这位主角的女友太受冷落了啊。</p>
<div id="attachment_966" class="wp-caption alignnone" style="width: 157px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_Ilia.jpg" alt="zelda_tp_Ilia" title="zelda_tp_Ilia" width="147" height="345" class="size-full wp-image-966 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">伊莉娅（Ilia）</p></div>
<h3><a name="Ooccoo">欧库 &#038; 小欧库（Ooccoo &#038; Ooccoo Jr.）</a></h3>
<p>天空之城的居民，因为某种原因来到了海拉尔大陆。为了寻找回到天空城的道路，她和自己的孩子不断穿梭在大陆的迷宫中寻找线索，并用魔法帮助林克脱离险境。最后在林克、米德娜和暗影帝国反击队的共同协助下回到了自己的故乡。</p>
<p>真的是非常非常有用的哦！</p>
<div id="attachment_967" class="wp-caption alignnone" style="width: 229px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_Ooccoo.jpg" alt="zelda_tp_Ooccoo" title="zelda_tp_Ooccoo" width="219" height="345" class="size-full wp-image-967 wp-caption wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">欧库 &#038; 小欧库（Ooccoo &#038; Ooccoo Jr.）</p></div>
<h3><a name="GorCoron">戈隆长老：戈·克隆（Gor Coron）</a></h3>
<p>戈隆族四大长老之一，拥有非同寻常的力量和智慧，领导着自己的子民看守着死亡之山上的矿藏圣地。虽然因为暗影力量的侵袭而与卡卡里科村的居民产生们了矛盾，但在林克解救了矿山内被操纵的伙伴后，重新与光之世界的居民建立起良好的关系。</p>
<div id="attachment_970" class="wp-caption alignnone" style="width: 249px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_GorCoron.jpg" alt="zelda_tp_GorCoron" title="zelda_tp_GorCoron" width="239" height="336" class="size-full wp-image-970 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">戈隆长老：戈·克隆（Gor Coron）</p></div>
<h3><a name="KingOrcsBulblin">兽王：布尔布林（King Orcs Bulblin）</a></h3>
<p>居住在大陆东方兽族部落的酋长，带领着自己强悍的军队统治着自己的领地。暗影军队入侵后，崇尚力量的他屈服在黎明之国的魔力下，成为魔王赞特的手下。绑架了奥东村的孩子们，并与林克数次作战。在最后的战斗中终于承认了林克的实力，并退出了光与暗的争斗。</p>
<div id="attachment_971" class="wp-caption alignnone" style="width: 368px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_KingOrcsBulblin.jpg" alt="zelda_tp_KingOrcsBulblin" title="zelda_tp_KingOrcsBulblin" width="358" height="340" class="size-full wp-image-971 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">兽王：布尔布林（King Orcs Bulblin）</p></div>
<h3><a name="ShadowBeing">暗影使者（Shadow Being）</a></h3>
<p>来自黎明之国的黑暗使者，拥有打开黎明之国和光之国之间时空隧道的能力，在赞特的带领下前往光之国与塞尔达公主的部队战斗。由于拥有特殊的能力，林克击败他们后，在米德娜的帮助下可以方便的穿梭在海拉尔大陆的各个角落。</p>
<div id="attachment_972" class="wp-caption alignnone" style="width: 343px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_ShadowBeing.jpg" alt="zelda_tp_ShadowBeing" title="zelda_tp_ShadowBeing" width="333" height="345" class="size-full wp-image-972 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">暗影使者（Shadow Being）</p></div>
<h3><a name="Zant">赞特（Zant）</a></h3>
<p>本是黎明之国中普通的魔法师，渴望拥有强大力量和权利的野心侵蚀了自己的心，在偶然的机会中获得了魔王加农道夫的力量，并在他的操纵下篡夺了黎明公主的王位。觊觎光之世界的他破坏了光与暗的平衡，率领着强大的暗之军团横行世界。</p>
<div id="attachment_973" class="wp-caption alignnone" style="width: 203px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_Zant.jpg" alt="zelda_tp_Zant" title="zelda_tp_Zant" width="193" height="345" class="size-full wp-image-973 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">赞特（Zant）</p></div>
<h3><a name="Ganondorf">加农道夫（Ganondorf）</a></h3>
<p>曾经是女神选择的勇士，拥有终极的三角力量。由于残暴的本性而被女神诅咒，成为了横行于古代历史的恶贼。受伤后的他被光明力量和仲裁者们封印在了黎明之国。不曾想他利用赞特恢复了自己的元气，并重新渴望统治整个世界。</p>
<p>不知道林克将来会不会也变成这样呢？应该不会吧！</p>
<div id="attachment_974" class="wp-caption alignnone" style="width: 467px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_Ganondorf.jpg" alt="zelda_tp_Ganondorf" title="zelda_tp_Ganondorf" width="457" height="238" class="size-full wp-image-974 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">加农道夫（Ganondorf）</p></div>
<h3><a name="TwilightPrincess">黎明公主（Twilight Princess）</a></h3>
<p>黎明世界的统治者，迷一般的角色，她的真实身份是……</p>
<p>或者应该说“她是……的真实身份”吧。</p>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_TwilightPrincess.jpg"><div id="attachment_975" class="wp-caption alignnone" style="width: 710px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_TwilightPrincess-700x466.jpg" alt="zelda_tp_TwilightPrincess" title="zelda_tp_TwilightPrincess" width="700" height="466" class="size-large wp-image-975 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">黎明公主（Twilight Princess）</p></div></a></p>
<p>虽然已经好久没玩了，但依稀还能记得那些人物们的对话、语气，好怀念啊。</p>
<hr />
<p>参考：</p>
<ul>
<li><a href="http://wii.tgbus.com/glmj/gl/200611/20061129114849.shtml" target="_blank">《塞尔达传说：黄昏公主》图文全攻略</a> by WiiBBS 攻研部 Szh、三代鬼彻、天堂的翅膀</li>
</ul>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/zelda-tp-intro.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：剧情介绍'>《塞尔达传说：黎明公主》攻略：剧情介绍</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch1.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：初章 英雄传说的扉页'>《塞尔达传说：黎明公主》攻略：初章 英雄传说的扉页</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch3.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：第三章 深海鱼族的传说'>《塞尔达传说：黎明公主》攻略：第三章 深海鱼族的传说</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch2.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：第二章 死亡山颠的咆哮'>《塞尔达传说：黎明公主》攻略：第二章 死亡山颠的咆哮</a></li>
<li><a href='http://www.gocalf.com/blog/check-udisk.html' rel='bookmark' title='U盘检测软件：ChipGenius，MyDiskTest'>U盘检测软件：ChipGenius，MyDiskTest</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/zelda-tp-characters.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[《塞尔达传说：黎明公主》攻略]]></series:name>
	</item>
		<item>
		<title>Dell E6400升级到MacOS 10.6.8</title>
		<link>http://www.gocalf.com/blog/dell-e6400-mac-10-6-8.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=dell-e6400-mac-10-6-8</link>
		<comments>http://www.gocalf.com/blog/dell-e6400-mac-10-6-8.html#comments</comments>
		<pubDate>Fri, 26 Aug 2011 15:48:39 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[操作系统]]></category>
		<category><![CDATA[BootThink]]></category>
		<category><![CDATA[Dell E6400]]></category>
		<category><![CDATA[Hackintosh]]></category>
		<category><![CDATA[MacOS]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[PC]]></category>
		<category><![CDATA[PC机装Mac]]></category>
		<category><![CDATA[SL 10.6.8]]></category>
		<category><![CDATA[升级]]></category>
		<category><![CDATA[雪豹]]></category>
		<category><![CDATA[黑苹果]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=925</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/mac_10.6.8.png" class="attachment-post-thumbnail wp-post-image" alt="mac_10.6.8" title="mac_10.6.8" /></div>半年前安装黑苹果的经历，装的是10.6.3。最近由于有些软件需要较高版本的系统，不得不对系统进行升级，升级到雪豹的最后一个版本10.6.8。升级后自然又遇到了一堆问题并逐一解决。解决得算是基本完美了，只差我那全球无解的Intel WiFi Link 5300 AGN无线网卡和不能休眠的问题。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/mac_10.6.8.png" class="attachment-post-thumbnail wp-post-image" alt="mac_10.6.8" title="mac_10.6.8" /></div><p>在<a href="http://www.gocalf.com/blog/dell-e6400-install-mac.html">Dell E6400安装MacOS雪豹10.6</a>中介绍了半年前安装黑苹果的经历，当时安装的版本其实是10.6.3。最近由于有些软件需要较高版本的系统，不得不对系统进行升级，升级到雪豹的最后一个版本10.6.8。升级后自然又遇到了一堆问题并逐一解决。解决得算是基本完美了，只差我那全球无解的Intel WiFi Link 5300 AGN无线网卡和不能休眠的问题。<span id="more-925"></span></p>
<p>还是上次那台机器，硬件配置完全没有变，就不再重复了。黑苹果之所以难装，除了核心的破解之外就全是驱动的问题了，来看看这次都遇到了哪些问题又是如何解决的。</p>
<p>前天（8月24日）晚上，决定要升级系统（没过多久，老乔就辞职了，都怪我啊，hoho）。直接在系统里面点击Software Update，用了两个多小时下载了升级包。昨天早晨爬起来之后点击更新，很快就装好了，重启，不出所料地白苹果了。</p>
<p>我们知道黑苹果常见的启动错误形式有：白苹果（灰白色背景上一个灰色的苹果图标，再无进展）、无限风火轮（在刚才那个苹果图片下面有一个风火轮在转动，但再无进展）和四国/五国（以四种/五种语言书写的当机提示）。这种情况下就只能长按电源键强制关机了。</p>
<p>再次开机，在BootThink引导的时候输入-v进入verbose模式，查看系统hang在什么地方。发现在显示了[PCI configuration end]之后就停住了，这似乎是Snow Leopard 10.6.8和Lion 10.7.1都会遇到的问题呢，原来是IOPCIFamily.kext和AppleACPIPlatform.kext被更新了，解决办法简单粗暴，直接找个老版本（10.6.7）的替换回去就好了。不过我把它们放在BootThink的Darwain\System\LibrarySL\Extensions\里面并不能解决问题，得要放到Mac分区去。如果有安装盘，可以用BootThink引导安装盘，在Console里面进行复制的操作，但我上次用来安装的硬盘分区早就格式化掉了，只好用<a href="http://bbs.pcbeta.com/forum-viewthread-tid-860881-highlight-macdriver.html" target="_blank">MacDrive（v8.0.5.31）</a>来操作。把那两个kext复制到Mac所在分区的/System/Library/Extensions里。</p>
<p>再次启动Mac OS，刚才的问题没有了，这次遇到的是Can't load kext com.apple.driver.AudioIPCDriver, link fail。要删掉BootThink里的VoodooHDA.kext。不过这样不就不能驱动声卡了吗？先不管它了。</p>
<p>接下来遇到的是FakeSMC: key info not found MSDS, length -6。看来我的FakeSMC.kext太古老了，找了个新版本的放进BootThink就好了。</p>
<p>然后又发现在显示了NTFS Volume xxxx, version 3.1之后，系统又hang住了。不知道到底为什么，但放了一个原版声卡驱动AppleHDA.kext进来就好了。（简直是有病乱投医啊）</p>
<p>再次启动，顺利进入系统，很开心。但是声卡没有驱动起来呢，是因为之前把VoodooHDA.kext去掉的原因吗？傻乎乎地又把它放回来，竟然没有当机，成功进入系统。这回有声卡了，但是没有声音，汗。换了个VoodooHDA.kext，hoho，有声音了。可是音量无法改变，即使静音状态也是一样大的声音。似乎也有人遇到类似的问题呢，又更新了一下VoodooHDA.kext，这次音量调节也正常了。</p>
<p>在更新我所需要的软件的时候，还有插入优盘的时候，都遇到个错误提示，说是the system extension /System/Library/Extensions/IOPCIFamily.kext was installed improperly and cannot be used.（或者是AppleACPIPlatform.kext）。这不是刚才替换的那两个老版本的文件么，啊，想起来了，刚才在Win 7里用MacDrive把两个文件复制过去之后，还应该要修改权限并删除缓存呢，这些都还没有做，能让我把系统启动起来就很不错了。赶紧打开Console，依次输入下面这些命令（如果当前用户不是root，还需要在命令前面加sudo）（另外命令中的<code class="codecolorer text geshi"><span class="text">Mac\ OS</span></code>需要替换成你的Mac系统所在分区的卷标）（忘了试一试直接用/System/Linrary行不行了，应该是同一个目录的）：</p>
<pre><div class="codecolorer-container bash geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #000000; font-weight: bold;">/</span>Volumes<span style="color: #000000; font-weight: bold;">/</span>Mac\ OS<span style="color: #000000; font-weight: bold;">/</span>System<span style="color: #000000; font-weight: bold;">/</span>Library<br />
<span style="color: #c20cb9; font-weight: bold;">chmod</span> <span style="color: #660033;">-R</span> <span style="color: #000000;">755</span> Extensions<br />
<span style="color: #c20cb9; font-weight: bold;">chown</span> <span style="color: #660033;">-R</span> root:wheel Extensions<br />
kextcache <span style="color: #660033;">-v</span> <span style="color: #000000;">1</span> <span style="color: #660033;">-l</span> <span style="color: #660033;">-s</span> <span style="color: #660033;">-n</span> <span style="color: #660033;">-t</span> <span style="color: #660033;">-arch</span> i386 <span style="color: #660033;">-arch</span> x86_64 <span style="color: #660033;">-m</span> <span style="color: #000000; font-weight: bold;">/</span>Volumes<span style="color: #000000; font-weight: bold;">/</span>Mac\ OS<span style="color: #000000; font-weight: bold;">/</span>System<span style="color: #000000; font-weight: bold;">/</span>Library<span style="color: #000000; font-weight: bold;">/</span>Caches<span style="color: #000000; font-weight: bold;">/</span>com.apple.kext.caches<span style="color: #000000; font-weight: bold;">/</span>Startup<span style="color: #000000; font-weight: bold;">/</span>Extensions.mkext <span style="color: #000000; font-weight: bold;">/</span>Volumes<span style="color: #000000; font-weight: bold;">/</span>Mac\ OS<span style="color: #000000; font-weight: bold;">/</span>System<span style="color: #000000; font-weight: bold;">/</span>Library<span style="color: #000000; font-weight: bold;">/</span>Extensions</div></div></pre>
<p>完成之后重启系统，就不会再遇到那样的错误提示了。</p>
<p>好像都完成了呢，兴冲冲地准备截图纪念，但是……按了Cmd+Shift+3之后，听到咔嚓一声，但桌面上却什么都没出来，咋回事呢？看样子显卡驱动也有问题，虽然可以调节分辨率，但无法截屏，也无法用系统自带的Previewer查看图片（双击打开图片只能看到白色）。唉，继续奋斗。</p>
<p>我之前用的显卡驱动是NVinject 0.2.1，改成最新的0.2.2也不好使，而且更差劲，连分辨率都无法改变了。找了好久，其实我以前用的是NVEnabler64，但上次装10.6.3的时候就不能使用了（因为我用的是32位吧），这次也没有希望。最后还是投入DSDT的怀抱。不过我可不会写DSDT，在网上找了一个（<a href="http://bbs.pcbeta.com/viewthread-804563-1-1.html" target="_blank">http://bbs.pcbeta.com/viewthread-804563-1-1.html</a>），号称搞定了关机、重启、休眠、断电、原生电源管理、原生显卡驱动、解决BIOS重置、以及将BCM无线网卡识别为内置。把NVinject.kext去掉，把dsdt.aml放在BootThink的Darwin目录下。重启电脑，Win 7突然蓝屏了，不知道怎么回事。不管它。</p>
<p>启动Mac，又不动了，似乎是声卡出问题了，暂时把VoodooHDA.kext去掉吧。顺利进入系统，刚登录的时候就已经感觉到不同了，很明显地登录窗口的动态效果、系统状态栏的半透明都是以前没有的。测试一下，果然可以截图、可以双击查看图片了，分辨率调节也有，不错。而且测试了一下关机断电，也没问题呢，之前10.6.3的时候其实关机是不会断电的，每次我都是重启然后在按电源键关机。</p>
<p>刚才那个dsdt.aml既然能够解决那么多问题，就意味着我可以去掉好多kext了，总共去掉了以下这些kext：</p>
<ul>
<li>NullCPUPowerManagement.kext：禁用电源管理，解决IntelCPUPowerManagement.kext的HPET错误。</li>
<li>OpenHaltRestart.kext：解决重启或关机问题。</li>
<li>OSXRestart.kext：解决重启问题。</li>
<li>PlatformUUID.kext：解决UUID错误。</li>
<li>IOAHCIBlockStorageInjector.kext：解决本地硬盘图标为橙色的补丁。</li>
<li>AppleRTC.kext：装10.6.3的时候不知道这是干什么用的，但似乎是Real Time Clock的驱动，应该是修改过的，主要是解决某些主板上，睡眠唤醒后BIOS重置的问题。</li>
<li>LegacyAppleAirPortBrcm4311.kext：BRCM无线网卡的驱动，对我来说根本没用，上次放着它主要是希望奇迹能够发生，然而我那个无线网卡身上似乎不会有奇迹出现。</li>
</ul>
<p>最后还是要面对声卡的问题，我又尝试着把AppleHDA.kext去掉，换上VoodooHDA.kext，嘿，还真就好了。不知道最开始的时候有VoodooHDA.kext，为什么还必须放AppleHDA.kext。或者因为我之前那个VoodooHDA.kext太老了吧。</p>
<p>除了wifi不能用之外还有个问题，就是这次没办法休眠了（10.6.3的时候好像是可以的）。不过据说10.6.8和Lion的休眠都很难，得拼人品。我是放弃了，因为SleepEnabler.kext跟10.6.8也不兼容呢，等更新吧。现在如果休眠的话，屏幕变黑，然后就什么都没有了，睡不下去，也叫不起来，只能强制关机。还好我很少用休眠。</p>
<p>呼，冒险升了次级，结果还是比较满意的，截图纪念。</p>
<div id="attachment_927" class="wp-caption alignnone" style="width: 331px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/mac_10.6.8_screenshot.png" alt="Mac OS 10.6.8 on Dell E6400" title="mac_10.6.8_screenshot" width="321" height="393" class="size-full wp-image-927 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">Mac OS SL 10.6.8 on Dell E6400</p></div>
<p>最后把用到的kext之类的都放在这里吧。</p>
<ul>
<li>放在BootThink的Darwin目录下：
<ul>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/dsdt.aml_.zip">dsdt.aml</a>：可以搞定关机、重启、休眠、断电、原生电源管理、原生显卡驱动、解决BIOS重置、以及将BCM无线网卡识别为内置。</li>
</ul>
</li>
<li>放在BootThink的Darwin\System\LibrarySL\Extensions目录下：
<ul>
<li>系统补丁
<ul>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/FakeSMC.kext_.zip">FakeSMC.kext</a>：黑苹果机必须的！一方面是对Mac OS必须的AppleSMC.kext（System Management Controller）的模拟；另一方面仿造苹果的Dont Steal Mac OS X.kext（苹果系统与苹果机器EFI模块之间的通信加密解密）。</li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/Disabler.kext_.zip">Disabler.kext</a>：屏蔽不能正常启动的补丁。</li>
</ul>
</li>
<li>Audio
<ul>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/IOAudioFamily.kext_.zip">IOAudioFamily.kext</a>：基本的声卡驱动框架。</li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/OSvKernDSPLib.kext_.zip">OSvKernDSPLib.kext</a>：内核的数字音频信号处理库。</li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/HDAEnabler.kext_.zip">HDAEnabler.kext</a></li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/VoodooHDA.kext_.zip">VoodooHDA.kext</a></li>
</ul>
</li>
<li>Ethernet
<ul>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/IONetworkingFamily.kext_.zip">IONetworkingFamily.kext</a>：基本的网卡驱动，有些网卡可以直接驱动。里面包含AppleBCM5701Ethernet.kext，AppleIntel8254XEthernet.kext，AppleRTL8139Ethernet.kext，AppleRTL8169Ethernet.kext，AppleUSBEthernet.kext，AppleUSBGigEthernet.kext，AppleYukon2.kext，Intel82574L.kext，nvenet.kext。</li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/Intel82566MM.kext_.zip">Intel82566MM.kext</a></li>
</ul>
</li>
<li>PS/2（鼠标、键盘、触摸板）
<ul>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/ApplePS2Controller.kext_.zip">ApplePS2Controller.kext</a></li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/AppleACPIPS2Nub.kext_.zip">AppleACPIPS2Nub.kext</a></li>
</ul>
</li>
<li>电源管理、Battery
<ul>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/AppleACPIPlatform.kext_.zip">AppleACPIPlatform.kext</a>：（升级到10.6.8后要复制到Mac分区的/System/Library/Extensions，修改权限并更新缓存）这是Advanced Configuration and Power Interface高级配置和电源管理接口驱动，进行电源管理，睡眠，Real-Time Clock控制等，其下还包含AppleACPIButtons.kext，AppleACPIEC.kext，AppleACPIPCI.kext。</li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/IOACPIFamily.kext_.zip">IOACPIFamily.kext</a>：作用于支持ACPI电源管理标准的驱动，例如电源按钮、电池、PS/2、USB、HPET等。这里的这个解决了部分笔记本风扇不正常问题，只支持32位。</li>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/VoodooBattery.kext_.zip">VoodooBattery.kext</a></li>
</ul>
</li>
<li>Bluetooth
<ul>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/DellBluetoothHCI.kext_.zip">DellBluetoothHCI.kext</a></li>
</ul>
</li>
<li>SD Reader
<ul>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/VoodooSDHC.kext_.zip">VoodooSDHC.kext</a></li>
</ul>
</li>
<li>PCMCIA
<ul>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/IOPCIFamily.kext_.zip">IOPCIFamily.kext</a>：（升级到10.6.8后要复制到Mac分区的/System/Library/Extensions，修改权限并更新缓存）PCI设备的基本驱动。</li>
</ul>
</li>
<li>Chip set
<ul>
<li><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/AHCIPortInjector.kext_.zip">AHCIPortInjector.kext</a>：可以识别Intel芯片组的AHCI（如果无法正确识别AHCI，启动时有可能会hang在Still Waiting for Root Device）。</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>继续啃苹果咯～</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/dell-e6400-install-mac.html' rel='bookmark' title='Dell E6400安装MacOS雪豹10.6'>Dell E6400安装MacOS雪豹10.6</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/dell-e6400-mac-10-6-8.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>《塞尔达传说：黎明公主》攻略：剧情介绍</title>
		<link>http://www.gocalf.com/blog/zelda-tp-intro.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=zelda-tp-intro</link>
		<comments>http://www.gocalf.com/blog/zelda-tp-intro.html#comments</comments>
		<pubDate>Sun, 21 Aug 2011 16:28:07 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[游戏]]></category>
		<category><![CDATA[Game]]></category>
		<category><![CDATA[Twilight Princess]]></category>
		<category><![CDATA[Wii]]></category>
		<category><![CDATA[任天堂]]></category>
		<category><![CDATA[塞尔达传说]]></category>
		<category><![CDATA[游戏攻略]]></category>
		<category><![CDATA[黄昏公主]]></category>
		<category><![CDATA[黎明公主]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=916</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_logo.png" class="attachment-post-thumbnail wp-post-image" alt="TheLegendOfZelda-TwilightPrincess Logo" title="zelda_tp_logo" /></div>前年的时候花了好多个晚上的时间在Wii上玩了《塞尔达传说：黎明公主》（The Legend of Zelda: Twilight Princess），真的是很不错的游戏呢。当时搜了很多的攻略，现在就贴在这里吧。基本上是参考了网上已有的攻略，但结合自己的实践也做了整理和修订。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_logo.png" class="attachment-post-thumbnail wp-post-image" alt="TheLegendOfZelda-TwilightPrincess Logo" title="zelda_tp_logo" /></div><p>前年的时候花了好多个晚上的时间在Wii上玩了《<a href="http://www.zelda.com/tp/" target="_blank">塞尔达传说：黎明公主</a>》（<a href="http://www.zelda.com/tp/" target="_blank">The Legend of Zelda: Twilight Princess</a>），真的是很不错的游戏呢。</p>
<p>当时搜了很多的攻略，现在就贴在这里吧。基本上是参考了网上已有的攻略，但结合自己的实践也做了整理和修订。<span id="more-916"></span></p>
<p>由于内容非常多，将会以系列文章的形式发布。今天这篇就只是个简单的开始。所有的文章如果有参考了其他人的作品，会在文章底部附加“参考”项。图片几乎全部来自参考的文章，但有些是我重新整理的，这种图片会打上GoCalf的水印。</p>
<p>另外关于这个游戏的中文名字，网上说法不一，主标题《塞尔达传说》肯定是没有疑问了，但副标题 Twilight Princess 则有多种翻译，有“曙光公主”、“黎明公主”、“黄昏公主”等等，似乎“黄昏公主”是比较普遍的叫法，但因为我的游戏里显示的是“黎明公主”，我就实在难以接受其他的名称了。所以我整理的攻略中将全部使用“黎明公主”这一说法。</p>
<div id="attachment_921" class="wp-caption alignnone" style="width: 650px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_logo_mid.png" alt="Zelda Twilight Princess Logo" title="zelda_tp_logo_mid" width="640" height="443" class="size-full wp-image-921 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">《塞尔达传说：黎明公主》LOGO</p></div>
<p><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_cover.jpg"><div id="attachment_922" class="wp-caption alignnone" style="width: 555px"><img src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/zelda_tp_cover-545x700.jpg" alt="Zelda Twilight Princess Cover" title="zelda_tp_cover" width="545" height="700" class="size-large wp-image-922 wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone wp-caption alignnone" /><p class="wp-caption-text">《塞尔达传说：黎明公主》封面、海报</p></div></a></p>
<p>随着美版Wii的首发，玩家们期盼已久的《塞尔达传说：黎明公主》终于与大家见面了，这款被任天堂寄予厚望的作品一再延期，也从最初预计的 NGC平台转移到了Wii上面，其重要性不言而喻。新生的塞尔达，以其卓越的世界观、精巧的迷题，用写实的风格让玩家体验最原始的感动，当你闭上眼睛，一切都会变成脑海里最精美的画面。</p>
<p>当黑暗感染大地，传说翻开了新的一页，凄凉的嚎声响彻风中，眼前烟波浩淼，耳边泣泣悲鸣，谁能将夜空划破，寻找黎明……</p>
<p>（注本攻略流程同样适用于NGC版，NGC版中林克为左手执剑，且游戏场景与Wii版呈镜像相反）</p>
<p>在古老而富饶的海拉尔大陆上，光之公主和黎明公主统治着自己的国家。有如黑夜和白昼的交替轮转，阳光下的光之国与黑暗中的黎明之国互不来往，和平地度过了数百万年……</p>
<p>然而，平淡的生活被突如其来的黑暗所打破，黑暗的使者凭借着其强大的魔力侵占了海拉尔城堡，为了自己子民的性命，光之公主不得不屈服在暗夜的威胁下，海拉尔的世界被笼罩在令人恐惧的黑暗中……</p>
<p>南方森林中的奥东小镇上，居住着一位名叫林克的年轻勇士，从未走出过村庄的他，与心爱之人和朋友们宁静的生活着，享受着最后的静逸。小镇当然也摆脱不了黑暗的侵袭，强悍的兽人抓走了镇里的孩子和林克的心上人，当他不顾一切追击兽人之时，却被一只魔力之手拖进了无尽的黑暗中……</p>
<p>当林克醒来之时，发现自己身处在薄雾中的暗淡世界里，四周弥漫着死亡的气息，而更加令他惊讶的是，自己居然变成了一匹狼——在黑暗中放纵兽行的野兽。自称为米德娜的生物嘲讽着狼形的林克。为了能够恢复原貌，重新开始自己的征程，林克不得不与这个乖僻性格中隐藏着善良的生物一起冒险，帮其寻找她所丢失神秘物品…… 在经历了种种磨砺之后，林克得知原来自己就是女神所选择的勇士，肩负着拯救水深火热中的海拉尔大陆的命运，为了让世界恢复和平，拥有野兽魔力的林克勇敢的冲向了海拉尔城堡……</p>
<p>在那里等待着他的，除了可怕的怪物和荆棘的道路外，还有光之公主与黎明公主殷切的期盼……</p>
<h4>剧情流程目录</h4>
<ul>
<li><a href="http://www.gocalf.com/blog/zelda-tp-into.html">剧情介绍</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-characters.html">主要角色简介</a></li>
<li>上部：光之精灵篇
<ul>
<li><a href="http://www.gocalf.com/blog/zelda-tp-ch1.html">初章 英雄传说的扉页（被神选中的少年）</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-ch2.html">第二章 死亡山巅的咆哮（大地的子民）</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-ch3.html">第三章 深海鱼族的传说（最后的影之碎片）</a></li>
</ul>
</li>
<li>下部：影之公主篇
<ul>
<li><a href="http://www.gocalf.com/blog/zelda-tp-ch4.html">第四章 沙漠深处的审判（死者之沙漠）</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-ch5.html">第五章 冰封魔镜的罪恶（雪山！兽人！爱！）</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-ch6.html">第六章 时间遗忘的裂缝（时之神殿）</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-ch7.html">第七章 天堂神殿的挽歌（天空之城）</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-ch8.html">第八章 黎明之前的黑暗（伪王）</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-ch9.html">第九章 斩破黑暗的利刃（黎明公主）</a></li>
</ul>
</li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-epilogue.html">终章 世界秩序的平衡（光与影）</a></li>
</ul>
<h4>附录部分</h4>
<ul>
<li><a href="http://www.gocalf.com/blog/zelda-tp-secret.html">必须要知道的几个秘密</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-heartpiece.html">心之碎片</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-item.html">非剧情道具</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-bottle.html">瓶子</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-mistery.html">奥义</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-goldenbug.html">金色虫</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-ghostsoul.html">鬼魂之魂</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-fishing.html">钓鱼</a></li>
<li><a href="http://www.gocalf.com/blog/zelda-tp-trialscave.html">试炼的洞窟</a></li>
<li>日版金手指文件下载：<a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/GoldenFinger_JP.zip">GoldenFinger_JP.zip</a></li>
</ul>
<hr />
<p>参考：</p>
<ul>
<li><a href="http://wii.tgbus.com/glmj/gl/200611/20061129114849.shtml" target="_blank">《塞尔达传说：黄昏公主》图文全攻略</a> by WiiBbs 攻研部 Szh、三代鬼彻、天堂的翅膀</li>
</ul>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/zelda-tp-characters.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：角色介绍'>《塞尔达传说：黎明公主》攻略：角色介绍</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch2.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：第二章 死亡山颠的咆哮'>《塞尔达传说：黎明公主》攻略：第二章 死亡山颠的咆哮</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch1.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：初章 英雄传说的扉页'>《塞尔达传说：黎明公主》攻略：初章 英雄传说的扉页</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-ch3.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：第三章 深海鱼族的传说'>《塞尔达传说：黎明公主》攻略：第三章 深海鱼族的传说</a></li>
<li><a href='http://www.gocalf.com/blog/check-udisk.html' rel='bookmark' title='U盘检测软件：ChipGenius，MyDiskTest'>U盘检测软件：ChipGenius，MyDiskTest</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/zelda-tp-intro.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[《塞尔达传说：黎明公主》攻略]]></series:name>
	</item>
		<item>
		<title>在循环有序数组中查找指定元素</title>
		<link>http://www.gocalf.com/blog/circularly-ordinal-array.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=circularly-ordinal-array</link>
		<comments>http://www.gocalf.com/blog/circularly-ordinal-array.html#comments</comments>
		<pubDate>Thu, 18 Aug 2011 16:05:00 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Binary Search]]></category>
		<category><![CDATA[二分查找]]></category>
		<category><![CDATA[循环有序数组]]></category>
		<category><![CDATA[有序数组]]></category>
		<category><![CDATA[查找算法]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=913</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/circular_ordinal_array.png" class="attachment-post-thumbnail wp-post-image" alt="circular_ordinal_array" title="circular_ordinal_array" /></div>问题描述：给定一个由n个各不相等的元素构成的循环有序数组（Circularly Ordinal Array），用 O(log n) 时间、O(1) 辅助空间在其中查找指定的元素。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/circular_ordinal_array.png" class="attachment-post-thumbnail wp-post-image" alt="circular_ordinal_array" title="circular_ordinal_array" /></div><p>这次的题目跟二分搜索有关，如果还不能写出正确的二分搜索，那就先找出课本温习一下吧。</p>
<p>问题描述：给定一个由n个各不相等的元素构成的循环有序数组（Circularly Ordinal Array），用 O(log n) 时间、O(1) 辅助空间在其中查找指定的元素。</p>
<p><span id="more-913"></span></p>
<p>所谓循环有序数组，就是把一个排好序（以升序排列为例）的数组从某个（未知）位置处截为两段，把前一段放到后一段的后面，所得到的数组。比如 { 8, 9, 10, 0, 1, 2, 3, 4, 5, 6, 7 }。如果把数组首尾相接，看成一个环形，那么数组就还是有序的，只不过最小值有可能在任何一个位置。从最小值开始向后，数值逐渐递增，到数组的最后一个元素时再回到第一个元素。</p>
<p>显然应用于普通的有序数组查找的二分算法已经无法直接使用了。如果已经知道了分界点（数组最小值或最大值）的位置，那问题就简单的多了，只要先判断一下待查元素是在分界点的左侧还是右侧，然后直接对那一侧的半个数组使用二分查找即可。</p>
<p>那么怎么找分界点呢？它的特点是它左边的所有元素都比它右边的元素大。借鉴二分查找的思想，首先取数组中间位置的元素，拿它跟两端的元素比较，分析出分界点是在左半边还是右半边，然后对包含分界点的那半个数组递归处理。</p>
<p>数组的第一个元素应该是在分界点左边最小的元素，但又不小于分界点右边的任何元素。那么如果中间位置的元素比它大，分界点就只能在中间元素的右边；反之，如果中间元素比它小，分界点就一定在左半边。由于题目中规定数组元素是个不相等的，这样的判断就足够了。</p>
<p>如果允许重复的元素，那就有可能遇到第一个元素与中间元素相等情况，这时需要再拿最后一个元素来比较，如果中间元素比最后一个元素大，分界点就在右半边；<strike>反之，如果中间元素比最后一个元素小，分界点就在左半边</strike>（感谢chasefornone的提醒，这种情况下，中间元素不会比最后一个元素小）。如果还是相等呢？</p>
<p>看看下面这张图中的两种情况（A和B），显然在第一次二分处理的时候，第一个（下标0）、中间的（下标12）和最后一个（下标24）元素都彼此相等，分界点却有可能在任何一边。这时候就只能分别对两半继续递归处理，时间复杂度可能会变成O(n)，空间复杂度可能会（不得不用递归或者栈来保存中间状态）变成O(log n)。</p>
<div id="attachment_915" class="wp-caption alignnone" style="width: 493px"><img alt="coa_special_case1" class="size-full wp-image-915 wp-caption alignnone wp-caption alignnone wp-caption alignnone" height="595" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/coa_special_case1.png" title="coa_special_case1" width="483" /><p class="wp-caption-text">有重复元素时的特殊情况：第一个、中间的和最后一个元素彼此相等</p></div>
<p>还是简单点儿，限定元素各不相同吧……</p>
<p>实际上，如果仔细考量上面的寻找分界点的方法，就会发现它跟二分查找是多么的相似啊。因此另外一种方法就是将二分查找算法修改一下，相当于把找分界点跟搜索指定元素结合起来。在每次二分的时候，除了跟中间值做比较外，也要跟两端的数值做比较，以此来确定对哪一半分治处理。直接写出这种方法下的查找函数算法：</p>
<div id="wp-tabs-7" class="wp-tabs wpui-light wpui-styles"><h3 class="wp-tab-title">Python</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> CycleBSearch<span style="color: black;">&#40;</span>arr<span style="color: #66cc66;">,</span> val<span style="color: black;">&#41;</span>:<br />
&nbsp; left <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span><br />
&nbsp; right <span style="color: #66cc66;">=</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>arr<span style="color: black;">&#41;</span> - <span style="color: #ff4500;">1</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> left <span style="color: #66cc66;">&lt;=</span> right:<br />
&nbsp; &nbsp; mid <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span>left + right<span style="color: black;">&#41;</span> / <span style="color: #ff4500;">2</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> val <span style="color: #66cc66;">==</span> arr<span style="color: black;">&#91;</span>mid<span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> mid &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #808080; font-style: italic;"># found val</span><br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> arr<span style="color: black;">&#91;</span>left<span style="color: black;">&#93;</span> <span style="color: #66cc66;">&lt;=</span> arr<span style="color: black;">&#91;</span>mid<span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> arr<span style="color: black;">&#91;</span>left<span style="color: black;">&#93;</span> <span style="color: #66cc66;">&lt;=</span> val <span style="color: #66cc66;">&lt;</span> arr<span style="color: black;">&#91;</span>mid<span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; right <span style="color: #66cc66;">=</span> mid - <span style="color: #ff4500;">1</span> &nbsp; <span style="color: #808080; font-style: italic;"># val is in left side</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; left <span style="color: #66cc66;">=</span> mid + <span style="color: #ff4500;">1</span> &nbsp; &nbsp;<span style="color: #808080; font-style: italic;"># val is in right side</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> arr<span style="color: black;">&#91;</span>left<span style="color: black;">&#93;</span> <span style="color: #66cc66;">&gt;</span> val <span style="color: #66cc66;">&gt;</span> arr<span style="color: black;">&#91;</span>mid<span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; left <span style="color: #66cc66;">=</span> mid + <span style="color: #ff4500;">1</span> &nbsp; &nbsp;<span style="color: #808080; font-style: italic;"># val is in right side</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; right <span style="color: #66cc66;">=</span> mid - <span style="color: #ff4500;">1</span> &nbsp; <span style="color: #808080; font-style: italic;"># val is in left side</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> -<span style="color: #ff4500;">1</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># cannot find val</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<h3 class="wp-tab-title">C++</h3>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container cpp geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include &lt;functional&gt;</span><br />
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> RandomAccessIterator, <span style="color: #0000ff;">class</span> T<span style="color: #000080;">&gt;</span><br />
RandomAccessIterator CycleBinarySearch<span style="color: #008000;">&#40;</span>RandomAccessIterator first,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RandomAccessIterator last,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">const</span> T<span style="color: #000040;">&amp;</span> value<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">return</span> CycleBinarySearch<span style="color: #008000;">&#40;</span>first, last, value, less<span style="color: #000080;">&lt;</span>T<span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #666666;">// A value, 'a', is considered equivalent to another, 'b', when</span><br />
<span style="color: #666666;">// (!comp(a, b) &amp;&amp; !comp(b, a)).</span><br />
<span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> RandomAccessIterator, <span style="color: #0000ff;">class</span> T, <span style="color: #0000ff;">class</span> Compare<span style="color: #000080;">&gt;</span><br />
RandomAccessIterator CycleBinarySearch<span style="color: #008000;">&#40;</span>RandomAccessIterator first,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RandomAccessIterator last,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">const</span> T<span style="color: #000040;">&amp;</span> value,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Compare comp<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; RandomAccessIterator left <span style="color: #000080;">=</span> first<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; RandomAccessIterator right <span style="color: #000080;">=</span> last <span style="color: #000040;">-</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>left <span style="color: #000080;">&lt;=</span> right<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; RandomAccessIterator mid <span style="color: #000080;">=</span> left <span style="color: #000040;">+</span> <span style="color: #008000;">&#40;</span>right <span style="color: #000040;">-</span> left<span style="color: #008000;">&#41;</span> <span style="color: #000040;">/</span> <span style="color: #0000dd;">2</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>comp<span style="color: #008000;">&#40;</span>value, <span style="color: #000040;">*</span>mid<span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;&amp;</span> <span style="color: #000040;">!</span>comp<span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>mid, value<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// find value</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">return</span> mid<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>comp<span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>mid, <span style="color: #000040;">*</span>left<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>comp<span style="color: #008000;">&#40;</span>value, <span style="color: #000040;">*</span>left<span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;&amp;</span> comp<span style="color: #008000;">&#40;</span>value, <span style="color: #000040;">*</span>mid<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// value could be in left side</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; right <span style="color: #000080;">=</span> mid <span style="color: #000040;">-</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// value could be in right side</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; left <span style="color: #000080;">=</span> mid <span style="color: #000040;">+</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>comp<span style="color: #008000;">&#40;</span>value, <span style="color: #000040;">*</span>left<span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;&amp;</span> comp<span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>mid, value<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// value could be in right side</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; left <span style="color: #000080;">=</span> mid <span style="color: #000040;">+</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// value could be in left side</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; right <span style="color: #000080;">=</span> mid <span style="color: #000040;">-</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666;">// cannot find value</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">return</span> last<span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></div><!-- end div.wp-tabs --></pre>
<p>话说我还是更喜欢 Python 啊。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
<li><a href='http://www.gocalf.com/blog/least-common-ancestor.html' rel='bookmark' title='求二叉树中两结点的最小公共祖先'>求二叉树中两结点的最小公共祖先</a></li>
<li><a href='http://www.gocalf.com/blog/calc-fibonacci.html' rel='bookmark' title='计算斐波纳契数，分析算法复杂度'>计算斐波纳契数，分析算法复杂度</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
<li><a href='http://www.gocalf.com/blog/unbalcanced-coin.html' rel='bookmark' title='利用不均匀硬币产生等概率'>利用不均匀硬币产生等概率</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/circularly-ordinal-array.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>彻底禁止游客访问Discuz! 7.0搭建的论坛</title>
		<link>http://www.gocalf.com/blog/discuz-no-anonymous.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=discuz-no-anonymous</link>
		<comments>http://www.gocalf.com/blog/discuz-no-anonymous.html#comments</comments>
		<pubDate>Mon, 15 Aug 2011 13:17:05 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[建站]]></category>
		<category><![CDATA[Anonymous]]></category>
		<category><![CDATA[Discuz!]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[匿名访问]]></category>
		<category><![CDATA[权限控制]]></category>
		<category><![CDATA[游客]]></category>
		<category><![CDATA[论坛]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=911</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/no_anonymous.png" class="attachment-post-thumbnail wp-post-image" alt="no_anonymous" title="no_anonymous" /></div>以前搭建了一个供内部交流用的 Discuz! 论坛，不希望没有账号的人（包括搜索引擎）看到论坛内的任何信息（包括首页等等）。在管理员设置里找了半天，发现可以“禁止IP”、“禁止用户访问”，甚至可以让“版主”、“超级版主”等用户组访问无法访问任何页面，却偏偏没有对游客的限制。对于大多数开放的论坛并无所谓，但对于我们这种特殊的论坛，就只好自己修改代码了。来看看是如何修改的。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/no_anonymous.png" class="attachment-post-thumbnail wp-post-image" alt="no_anonymous" title="no_anonymous" /></div><p>以前搭建了一个供内部交流用的 Discuz! 论坛，不希望没有账号的人（包括搜索引擎）看到论坛内的任何信息（包括首页等等）。在管理员设置里找了半天，发现可以“禁止IP”、“禁止用户访问”，甚至可以让“版主”、“超级版主”等用户组访问无法访问任何页面，却偏偏没有对游客的限制。对于大多数开放的论坛并无所谓，但对于我们这种特殊的论坛，就只好自己修改代码了。来看看是如何修改的。</p>
<span id="more-911"></span>
<p>此次修改针对的是 Discuz! 7.0，其他版本可能也大同小异吧。只要改一点点就好了。</p>
<p>文件/include/common.func.php中的代码几乎在访问论坛任何页面时都会被执行，它包含了很多对用户权限的控制，只要在恰当的位置添加对游客的访问限制即可。</p>
<p>要关注的代码段落是365行至378行：</p>
<pre><div class="codecolorer-container php geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>365<br />366<br />367<br />368<br />369<br />370<br />371<br />372<br />373<br />374<br />375<br />376<br />377<br />378<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><a href="http://www.php.net/empty"><span style="color: #990000;">empty</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_DCACHE</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'advs'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$globaladvs</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span><a href="http://www.php.net/defined"><span style="color: #990000;">defined</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'IN_ADMINCP'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #b1b100;">require_once</span> DISCUZ_ROOT<span style="color: #339933;">.</span><span style="color: #0000ff;">'./include/advertisements.inc.php'</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><a href="http://www.php.net/isset"><span style="color: #990000;">isset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$allowvisit</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$allowvisit</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span>CURSCRIPT <span style="color: #339933;">==</span> <span style="color: #0000ff;">'member'</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$action</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'groupexpiry'</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$action</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'activate'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; showmessage<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user_banned'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'HALTED'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span><a href="http://www.php.net/in_array"><span style="color: #990000;">in_array</span></a><span style="color: #009900;">&#40;</span>CURSCRIPT<span style="color: #339933;">,</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'logging'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'wap'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'seccode'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'ajax'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$adminid</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$bbclosed</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; clearcookies<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$closedreason</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">result_first</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;SELECT value FROM <span style="color: #006699; font-weight: bold;">{$tablepre}</span>settings WHERE variable='closedreason'&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; showmessage<span style="color: #009900;">&#40;</span><span style="color: #000088;">$closedreason</span> ? <span style="color: #000088;">$closedreason</span> <span style="color: #339933;">:</span> <span style="color: #0000ff;">'board_closed'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'NOPERM'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; periodscheck<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'visitbanperiods'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div></pre>
<p>从369行开始的那段代码是对被禁止的用户组或者账户进行屏蔽，以及处理论坛暂时关闭的情况，就在它前面加上对游客的限制即可。判断是游客还是已登录用户的方法就是看有没有uid信息，游客是没有uid的。另外，虽然游客不能访问论坛的任何页面，但总要让他能够注册或者登录，所以要把相关页面的权限放开。除了371行所列的那几项之外，还需要开放register，除非论坛注册也不对外开放。</p>
<p>修改的内容如下，只是多加了一个判断而已：</p>
<pre><div class="codecolorer-container diff geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="diff codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #440088;">368a369,374</span><br />
<span style="color: #00b000;">&gt; /* Forbid tourists visiting the bbs. Add by calf, Apr 15, 2009 */</span><br />
<span style="color: #00b000;">&gt; if<span style="">&#40;</span>!$discuz_uid &amp;&amp; !<span style="">&#40;</span>defined<span style="">&#40;</span>'CURSCRIPT'<span style="">&#41;</span> &amp;&amp; in_array<span style="">&#40;</span>CURSCRIPT, array<span style="">&#40;</span>'logging', 'wap', 'seccode', 'ajax', 'register'<span style="">&#41;</span><span style="">&#41;</span><span style="">&#41;</span><span style="">&#41;</span> <span style="">&#123;</span></span><br />
<span style="color: #00b000;">&gt; &nbsp; showmessage<span style="">&#40;</span>'not_loggedin', NULL, 'NOPERM'<span style="">&#41;</span>;</span><br />
<span style="color: #00b000;">&gt; <span style="">&#125;</span></span><br />
<span style="color: #00b000;">&gt; /* End of Add */</span><br />
<span style="color: #00b000;">&gt;</span></div></div></pre>
<p>这样修改后，未登录状态下访问论坛会得到类似于“您无权进行当前操作，这可能因以下原因之一造成：对不起，您还没有登录，无法进行此操作。”的提示信息，并直接跳转到登录界面。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/cpp-singleton.html' rel='bookmark' title='可以继承的C++ Singleton基类'>可以继承的C++ Singleton基类</a></li>
<li><a href='http://www.gocalf.com/blog/latex-plugin-more.html' rel='bookmark' title='关于LaTeX插件再啰嗦几句'>关于LaTeX插件再啰嗦几句</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/discuz-no-anonymous.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>可以继承的C++ Singleton基类</title>
		<link>http://www.gocalf.com/blog/cpp-singleton.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=cpp-singleton</link>
		<comments>http://www.gocalf.com/blog/cpp-singleton.html#comments</comments>
		<pubDate>Fri, 12 Aug 2011 15:20:12 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[程序开发]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Design Pattern]]></category>
		<category><![CDATA[Singleton]]></category>
		<category><![CDATA[单例]]></category>
		<category><![CDATA[模板类]]></category>
		<category><![CDATA[继承]]></category>
		<category><![CDATA[设计模式]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=906</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/singleton_class.png" class="attachment-post-thumbnail wp-post-image" alt="singleton_class" title="singleton_class" /></div>单例模式是设计模式中的一种，它用来保证系统中最多只能存在一个它的实例，其做法是由类自身来创建和持有它的对象实例，把对实例的创建权和管理权都控制在自己手中，以便控制实例数目。本文介绍可以继承的单例类。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/singleton_class.png" class="attachment-post-thumbnail wp-post-image" alt="singleton_class" title="singleton_class" /></div><p>单例模式（Singleton Pattern）是设计模式中的一种，它用来保证系统中最多只能存在一个它的实例，其做法是由类自身来创建和持有它的对象实例，把对实例的创建权和管理权都控制在自己手中，以便控制实例数目。</p>
<p>关于如何在C++中实现单例模式的讨论已经太多了，我只是简单介绍一下可以继承的单例类。</p>
<span id="more-906"></span>
<p>首先介绍一下通常所见的单例类的写法，不妨设这个类叫做Singleton。</p>
<p>Singleton.h：</p>
<pre><div class="codecolorer-container cpp geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#ifndef _SINGLETON_H_</span><br />
<span style="color: #339900;">#define _SINGLETON_H_</span><br />
<br />
<span style="color: #339900;">#include &lt;memory&gt;</span><br />
<br />
<span style="color: #0000ff;">class</span> Singleton<br />
<span style="color: #008000;">&#123;</span><br />
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">static</span> Singleton<span style="color: #000040;">&amp;</span> GetInstance<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; Singleton<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; ~Singleton<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666;">// Use auto_ptr to make sure that the allocated memory for instance</span><br />
&nbsp; &nbsp; <span style="color: #666666;">// will be released when program exits (after main() ends).</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">static</span> std<span style="color: #008080;">::</span><span style="color: #007788;">auto_ptr</span><span style="color: #000080;">&lt;</span>singleton<span style="color: #000080;">&gt;</span> s_instance<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">friend</span> <span style="color: #0000ff;">class</span> std<span style="color: #008080;">::</span><span style="color: #007788;">auto_ptr</span><span style="color: #000080;">&lt;</span>singleton<span style="color: #000080;">&gt;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; Singleton<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> Singleton<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; Singleton<span style="color: #000040;">&amp;</span> operator <span style="color: #000080;">=</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> Singleton<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #339900;">#endif</span></div></td></tr></tbody></table></div></singleton></singleton></memory></pre>
<p>Singleton.cpp：</p>
<pre><div class="codecolorer-container cpp geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include &quot;Singleton.h&quot;</span><br />
<span style="color: #339900;">#include &lt;iostream&gt;</span><br />
<span style="color: #339900;">#include &lt;boost thread.hpp=&quot;&quot;&gt;</span><br />
<br />
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> boost<span style="color: #008080;">;</span><br />
<br />
auto_ptr<span style="color: #000080;">&lt;</span>singleton<span style="color: #000080;">&gt;</span> Singleton<span style="color: #008080;">::</span><span style="color: #007788;">s_instance</span><span style="color: #008080;">;</span><br />
<br />
Singleton<span style="color: #008080;">::</span><span style="color: #007788;">Singleton</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;Construct Singleton&quot;</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
Singleton<span style="color: #008080;">::</span>~Singleton<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;Destruct Singleton&quot;</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
Singleton<span style="color: #000040;">&amp;</span> Singleton<span style="color: #008080;">::</span><span style="color: #007788;">GetInstance</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">static</span> mutex s_mutex<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>s_instance.<span style="color: #007788;">get</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">==</span> <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; mutex<span style="color: #008080;">::</span><span style="color: #007788;">scoped_lock</span> lock<span style="color: #008000;">&#40;</span>s_mutex<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>s_instance.<span style="color: #007788;">get</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">==</span> <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s_instance.<span style="color: #007788;">reset</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">new</span> Singleton<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// 'lock' will be destructed now. 's_mutex' will be unlocked.</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">return</span> <span style="color: #000040;">*</span>s_instance<span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div></singleton></boost></iostream></pre>
<p>这个类写的也不完美啦，比如双重判定也会有失效的时候，不过凑合用吧，哈哈。不过话说boost库里也有singleton，我为什么要自己写个呢，无奈地飘过。</p>
<p>废话不多说了，上面的单例类基本上解决了多线程安全问题、实例内存自动释放问题，算是一段可以使用的程序。不过如果系统中有大量单例类（这时候也得好好考虑一下design有没有问题），每个都要这么写一番岂不是很麻烦？要是可以写一个单例基类，以后再创造单例类的时候直接继承一下多方便啊。不过很明显的问题就在那个static对象指针，这个用来保存唯一实例的静态变量如果定义在基类里面，那所有的子类都只能用这同一个变量来保存它们各自的实例了，社会主义国家总得让每个子类都过上温饱生活吧！</p>
<p>以前的时候我还真不知道该怎么解决这个问题，但05年用了WTL（Windows Template Library）之后，我才意识到模板类可以帮助我（话说我真的是自己想到的，虽然现在搜一下能搜到一大堆）。这里要用的还不是普通的模板类，而是像ATL、WTL里面那样把要定义的类自身放入模板参数中，形如<code class="codecolorer cpp geshi"><span class="cpp"><span style="color: #0000ff;">class</span> MyClass <span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> Base<span style="color: #000080;">&lt;</span>myclass<span style="color: #000080;">&gt;</span> <span style="color: #008000;">&#123;</span> <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></span></code>。这样做有很多优点啦，最显著的比如不需要虚表（节省内存哦）、多态函数的调用在编译时就确定了（既加快了运行速度，也有利于编译器对代码进行优化）。</myclass></p>
<p>不妨把这个单例基类叫做ISingleton吧，看起来好像是个interface呢。代码如下：</p>
<pre><div class="codecolorer-container cpp geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#ifndef _ISingleton_H_</span><br />
<span style="color: #339900;">#define _ISingleton_H_</span><br />
<br />
<span style="color: #339900;">#include &lt;memory&gt;</span><br />
<span style="color: #339900;">#include &lt;boost thread.hpp=&quot;&quot;&gt;</span><br />
<br />
<span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">typename</span> t<span style="color: #000080;">=</span><span style="color: #FF0000;">&quot;&quot;</span><span style="color: #000080;">&gt;</span><br />
<span style="color: #0000ff;">class</span> ISingleton<br />
<span style="color: #008000;">&#123;</span><br />
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">static</span> T<span style="color: #000040;">&amp;</span> GetInstance<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">static</span> boost<span style="color: #008080;">::</span><span style="color: #007788;">mutex</span> s_mutex<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>s_instance.<span style="color: #007788;">get</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">==</span> <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; boost<span style="color: #008080;">::</span><span style="color: #007788;">mutex</span><span style="color: #008080;">::</span><span style="color: #007788;">scoped_lock</span> lock<span style="color: #008000;">&#40;</span>s_mutex<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>s_instance.<span style="color: #007788;">get</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">==</span> <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s_instance.<span style="color: #007788;">reset</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">new</span> T<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// 'lock' will be destructed now. 's_mutex' will be unlocked.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">return</span> <span style="color: #000040;">*</span>s_instance<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #0000ff;">protected</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; ISingleton<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; ~ISingleton<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #008000;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666;">// Use auto_ptr to make sure that the allocated memory for instance</span><br />
&nbsp; &nbsp; <span style="color: #666666;">// will be released when program exits (after main() ends).</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">static</span> std<span style="color: #008080;">::</span><span style="color: #007788;">auto_ptr</span><span style="color: #000080;">&lt;</span>t<span style="color: #000080;">&gt;</span> s_instance<span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; ISingleton<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> Singleton<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; ISingleton<span style="color: #000040;">&amp;</span> operator <span style="color: #000080;">=</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> ISingleton<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">typename</span> t<span style="color: #000080;">=</span><span style="color: #FF0000;">&quot;&quot;</span><span style="color: #000080;">&gt;</span><br />
std<span style="color: #008080;">::</span><span style="color: #007788;">auto_ptr</span><span style="color: #000080;">&lt;</span>t<span style="color: #000080;">&gt;</span> ISingleton<span style="color: #000080;">&lt;</span>t<span style="color: #000080;">&gt;</span><span style="color: #008080;">::</span><span style="color: #007788;">s_instance</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #339900;">#endif</span></div></td></tr></tbody></table></div></t></t></typename></t></typename></boost></memory></pre>
<p>要利用ISingleton创建一个自己的单例类，比如MySingleton，可以使用如下的代码：</p>
<pre><div class="codecolorer-container cpp geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include &quot;Singleton.h&quot;</span><br />
<span style="color: #339900;">#include &quot;ISingleton.h&quot;</span><br />
<span style="color: #339900;">#include &lt;iostream&gt;</span><br />
<br />
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">class</span> MySingleton <span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> ISingleton<span style="color: #000080;">&lt;</span>mysingleton<span style="color: #000080;">&gt;</span><br />
<span style="color: #008000;">&#123;</span><br />
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #666666;">// blah blah</span><br />
<br />
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; MySingleton<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;Construct MySingleton&quot;</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<br />
&nbsp; &nbsp; ~MySingleton<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;Destruct MySingleton&quot;</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #0000ff;">friend</span> ISingleton<span style="color: #000080;">&lt;</span>mysingleton<span style="color: #000080;">&gt;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">friend</span> <span style="color: #0000ff;">class</span> auto_ptr<span style="color: #000080;">&lt;</span>mysingleton<span style="color: #000080;">&gt;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; MySingleton<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> MySingleton<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; MySingleton<span style="color: #000040;">&amp;</span> operator <span style="color: #000080;">=</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> MySingleton<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div></mysingleton></mysingleton></mysingleton></iostream></pre>
<p>最最重要的，千万不要忘了把MySingleton的构造和析构函数弄成private的，还要添加两个友元。有人说ISingleton和MySingleton的析构函数都要加virtual，我倒是觉得没有必要呢，你说呢？另外要注意，MySingleton不能被继承哦。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/discuz-no-anonymous.html' rel='bookmark' title='彻底禁止游客访问Discuz! 7.0搭建的论坛'>彻底禁止游客访问Discuz! 7.0搭建的论坛</a></li>
<li><a href='http://www.gocalf.com/blog/cpp-const-and-pointer.html' rel='bookmark' title='C++中的常量指针和指针常量'>C++中的常量指针和指针常量</a></li>
<li><a href='http://www.gocalf.com/blog/random-selection.html' rel='bookmark' title='单次遍历，等概率随机选取问题'>单次遍历，等概率随机选取问题</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/cpp-singleton.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>星期万年历</title>
		<link>http://www.gocalf.com/blog/calendar-of-week.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=calendar-of-week</link>
		<comments>http://www.gocalf.com/blog/calendar-of-week.html#comments</comments>
		<pubDate>Wed, 10 Aug 2011 14:25:12 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[有用知识]]></category>
		<category><![CDATA[Calendar]]></category>
		<category><![CDATA[Day of Week]]></category>
		<category><![CDATA[Math]]></category>
		<category><![CDATA[万年历]]></category>
		<category><![CDATA[星期几]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=901</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/calendar_day_of_week.png" class="attachment-post-thumbnail wp-post-image" alt="calendar_day_of_week" title="calendar_day_of_week" /></div>小学的时候看到过计算某年某月某日是星期几的方法，当时觉得好神奇啊，当时一直不明白为什么一个简简单单的式子或者一张表格就能够算出任何一天是星期几呢。让我们回忆一下孩童时期的乐趣吧，或许以后可以用来逗孩子玩呢。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/calendar_day_of_week.png" class="attachment-post-thumbnail wp-post-image" alt="calendar_day_of_week" title="calendar_day_of_week" /></div><p>还记得小学的时候看到过计算某年某月某日是星期几的方法，当时觉得好神奇啊，当时一直不明白为什么一个简简单单的式子或者一张表格就能够算出任何一天是星期几呢，这些方法伴随我度过了整个童年。</p>
<p>长大后就知道了它们的原理，因为星期是七天为一个周期，只要已知某一天是星期几，要算任何一天是星期几只要求出两个日子之间的天数就可以了。现在的编程语言几乎全都包含了获得星期的方法，程序员们再也不用为此发愁。但还是让我们回忆一下孩童时期的乐趣吧，或许以后可以用来逗孩子玩呢。</p>
<p><span id="more-901"></span></p>
<h3>公式法计算星期几</h3>
<p>这是我最早知道的计算某一天是星期几的方法，还曾经在同学的Casio可编程计算器上做了个简单的程序来自动计算，真是有趣的回忆。</p>
<p>设Y是公元年数（比如今年的话，Y等于2011），D是从同年元旦到指定的这天未为止的天数（包含这一天，比如1月1号的话，D就是1），那么指定日期的星期数为：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_fbdc19fde87ff99fb20769dc0a594e02.gif' style='vertical-align: middle; border: none; ' class='tex' alt="W=\left ((Y-1)+\left \lfloor \frac{Y-1}{4} \right \rfloor-\left \lfloor \frac{Y-1}{100} \right \rfloor+\left \lfloor \frac{Y-1}{400} \right \rfloor+D \right )\bmod7" title="W=\left ((Y-1)+\left \lfloor \frac{Y-1}{4} \right \rfloor-\left \lfloor \frac{Y-1}{100} \right \rfloor+\left \lfloor \frac{Y-1}{400} \right \rfloor+D \right )\bmod7" /></span><script type='math/tex'>W=\left ((Y-1)+\left \lfloor \frac{Y-1}{4} \right \rfloor-\left \lfloor \frac{Y-1}{100} \right \rfloor+\left \lfloor \frac{Y-1}{400} \right \rfloor+D \right )\bmod7</script></p>
<p>结果0代表周日，1～6分别代表星期一～星期六。</p>
<p>以今天为例，2011年8月10日，先求出今年元旦到今天有多少天（包含今天），显然<code class="codecolorer text geshi"><span class="text">D=31+28+31+30+31+30+31+10=222</span></code>，代入公式得到：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_419b3b4ba7edaefd8f2c9557fa32446f.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{array}{rcl} W & = & \left ((2011-1)+\left \lfloor \frac{2011-1}{4} \right \rfloor-\left \lfloor \frac{2011-1}{100} \right \rfloor+\left \lfloor \frac{2011-1}{400} \right \rfloor+222 \right )\bmod7 \\ & = & \left (2010+502-20+5+222 \right )\bmod7 \\ & = & 2719\bmod7 \\ & = & 3\end{array}" title="\begin{array}{rcl} W & = & \left ((2011-1)+\left \lfloor \frac{2011-1}{4} \right \rfloor-\left \lfloor \frac{2011-1}{100} \right \rfloor+\left \lfloor \frac{2011-1}{400} \right \rfloor+222 \right )\bmod7 \\ & = & \left (2010+502-20+5+222 \right )\bmod7 \\ & = & 2719\bmod7 \\ & = & 3\end{array}" /></span><script type='math/tex'>\begin{array}{rcl} W & = & \left ((2011-1)+\left \lfloor \frac{2011-1}{4} \right \rfloor-\left \lfloor \frac{2011-1}{100} \right \rfloor+\left \lfloor \frac{2011-1}{400} \right \rfloor+222 \right )\bmod7 \\ & = & \left (2010+502-20+5+222 \right )\bmod7 \\ & = & 2719\bmod7 \\ & = & 3\end{array}</script></p>
<p>今天是周三，没错呢。</p>
<h3>表格法计算星期几</h3>
<p>上面的公式虽然简单明了，但对于小学时候的我却还是非常头疼的，四则运算不过关的人伤不起啊！下面这个表格法则没有任何计算了，我还特意添加了JavaScript使得它更容易使用。</p>
<p>使用方法非常简单，比如还是看今天是星期几，按照以下三步进行：</p>
<ol>
<li>在百年数区域里找到20，在年份后两位数字区域里找到11。由20所在横行向右，11所在竖行向下，交于F。</li>
<li>在月份区域里找到8，向左在同一横行里找到F。</li>
<li>在日期区域里找到10，在同一横行向左，同时由（第2步中找到的）F所在竖行向下，与10所在横行相交于星期区域里的“三”。</li>
</ol>
<p>可见同样求出今天是星期三。</p>
<p>另外注意在月份区域中的1'和2'分别表示闰年的1月和2月。比如算2000年1月某天是星期几，就要在月份区域里选择1'。</p>
<p>猛烈点击<a href="http://www.gocalf.com/blog/wp-content/uploads/2011/08/calendar_week.htm" target="_blank">这里（calendar_week.html）</a>可以在新的页面中打开星期万年历表格。如果你的浏览器支持IFRAME，可以在文章底部看到同样的表格。</p>
<h3>啰嗦两句</h3>
<p>根据公式或者表格都可以算出公元1年1月1日是星期一，那天到底是不是星期一呢？我不知道，而且也没有实际的意义，因为这个历法是罗马教皇格里高利十三世在1582年10月15日启用的，而英国及其殖民地直到1752年9月14日才使用现在的历法，所以算这之前甚至公元前某日是星期几毫无意义。另外，1582年2月24日教皇下令去除1582年10月5日至14日，1752年英国国会下令去除1752年9月3日至13日，所以1752年9月14日是星期四，但1752年9月2日却是星期三而不是星期六。 这也是为什么我在表格的百年数区域里从15开始写。</p>
<h3>附：放在IFRAME里面的星期万年历表格</h3>
<p><iframe frameborder="1" height="1060" name="星期万年历" scrolling="yes" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/calendar_week.htm" title="Week Calendar" width="100%"></iframe></p>
<h3>&nbsp;</h3>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
<li><a href='http://www.gocalf.com/blog/about-paper-size.html' rel='bookmark' title='纸张的尺寸：A、B、C号纸，纸张开本'>纸张的尺寸：A、B、C号纸，纸张开本</a></li>
<li><a href='http://www.gocalf.com/blog/latex-wordpress.html' rel='bookmark' title='WordPress数学公式插件LaTeX'>WordPress数学公式插件LaTeX</a></li>
<li><a href='http://www.gocalf.com/blog/circularly-ordinal-array.html' rel='bookmark' title='在循环有序数组中查找指定元素'>在循环有序数组中查找指定元素</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection-2.html' rel='bookmark' title='单次遍历，带权随机选取问题（二）'>单次遍历，带权随机选取问题（二）</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/calendar-of-week.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++中的常量指针和指针常量</title>
		<link>http://www.gocalf.com/blog/cpp-const-and-pointer.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=cpp-const-and-pointer</link>
		<comments>http://www.gocalf.com/blog/cpp-const-and-pointer.html#comments</comments>
		<pubDate>Thu, 04 Aug 2011 15:39:37 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[程序开发]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[const]]></category>
		<category><![CDATA[Const Pointer]]></category>
		<category><![CDATA[Pointer to Const]]></category>
		<category><![CDATA[指针]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=898</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/const_and_pointer.png" class="attachment-post-thumbnail wp-post-image" alt="const_and_pointer" title="const_and_pointer" /></div>仔细回忆一下C++中的指针常量与常量指针的区别，记录于此。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/const_and_pointer.png" class="attachment-post-thumbnail wp-post-image" alt="const_and_pointer" title="const_and_pointer" /></div><p>太久不用C++了，竟然连最基本的东西都记不清楚了。今天干活的时候突然想要用指针常量，但突然就忘了指针常量跟常量指针的区别。花了一点儿时间仔细回想了一下几年前上课时老师讲的，总算又回忆起来了，赶紧记录下来备忘。</p>
<p>这可能会被当作面试题，不过不是算法，故而不放在面试算法题系列中。</p>
<p><span id="more-898"></span></p>
<p>我觉得容易混淆的罪魁祸首在于中文的翻译问题，如果改叫“常量的指针”和“指针常量”可能会好些。先不管这些，看看英文的叫法：Pointer to Const 和 Const Pointer。</p>
<p>Pointer to Const，顾名思义就是一个指针，指向的数据不能被修改，C++语法是<code class="codecolorer cpp geshi"><span class="cpp"><span style="color: #0000ff;">int</span> <span style="color: #0000ff;">const</span><span style="color: #000040;">*</span> ptr</span></code>。怎么记忆呢，非常简单，记住要从右往左解读即可。首先这是个变量（<code class="codecolorer cpp geshi"><span class="cpp">ptr</span></code>）；然后发现它是个指针（<code class="codecolorer cpp geshi"><span class="cpp"><span style="color: #000040;">*</span></span></code>）；接下来看到它所指向的数据是不可修改的（<code class="codecolorer cpp geshi"><span class="cpp"><span style="color: #0000ff;">const</span></span></code>）；最后这个指针所指向的空间存放的是整数（<code class="codecolorer cpp geshi"><span class="cpp"><span style="color: #0000ff;">int</span></span></code>）。</p>
<p>Const Pointer，也是个指针，但这个指针的值不能被修改（不能再指向其他地方），C++语法是<code class="codecolorer cpp geshi"><span class="cpp"><span style="color: #0000ff;">int</span><span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span> ptr</span></code>。同样从右往左读，变量（<code class="codecolorer cpp geshi"><span class="cpp">ptr</span></code>）；变量的值不能被修改（<code class="codecolorer cpp geshi"><span class="cpp"><span style="color: #0000ff;">const</span></span></code>）；是个指针（<code class="codecolorer cpp geshi"><span class="cpp"><span style="color: #000040;">*</span></span></code>）；这个指针所指向的空间存放的是整数（<code class="codecolorer cpp geshi"><span class="cpp"><span style="color: #0000ff;">int</span></span></code>）。</p>
<p>可见const修饰的是它右边紧邻的元素，如果右边是指针*，就表明指针指向的是常量，不能被修改；如果右边是变量，就变明这个变量自身不能被修改。</p>
<p>下面这段C++程序示意了两种指针的区别，其中被注释掉的两行（高亮显示）是因为会无法编译。</p>
<pre><div class="codecolorer-container cpp geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">int</span> a1 <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span> b1 <span style="color: #000080;">=</span> <span style="color: #0000dd;">2</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span> c1 <span style="color: #000080;">=</span> <span style="color: #0000dd;">3</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">int</span><span style="color: #000040;">*</span> pointer <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>a1<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span> <span style="color: #0000ff;">const</span><span style="color: #000040;">*</span> pointerToConst <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>b1<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span><span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span> constPointer <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>c1<span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">int</span> a2 <span style="color: #000080;">=</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span> b2 <span style="color: #000080;">=</span> <span style="color: #0000dd;">20</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span> c2 <span style="color: #000080;">=</span> <span style="color: #0000dd;">30</span><span style="color: #008080;">;</span><br />
pointer <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>a2<span style="color: #008080;">;</span><br />
pointerToConst <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>b2<span style="color: #008080;">;</span><br />
<span style="display:block;background-color:#ffff66"><span style="color: #666666;">//constPointer = &amp;c2; &nbsp;// the pointer cannot be moved</span><br /></span><br />
<span style="color: #000040;">*</span>pointer <span style="color: #000040;">+</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">100</span><span style="color: #008080;">;</span><br />
<span style="display:block;background-color:#ffff66"><span style="color: #666666;">//*pointerToConst += 100; &nbsp;// the pointed data cannot be changed</span><br /></span><span style="color: #000040;">*</span>constPointer <span style="color: #000040;">+</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">100</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;*pointer = &quot;</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #000040;">*</span>pointer <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;*pointerToConst = &quot;</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #000040;">*</span>pointerToConst <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;*constPointer = &quot;</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #000040;">*</span>constPointer <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span></div></td></tr></tbody></table></div></pre>
<p>显然程序的输出应该是：</p>
<pre><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">*pointer = 110<br />
*pointerToConst = 20<br />
*constPointer = 103</div></div></pre>
<p>对英文名称理解清楚了，记不记中文名字也就无所谓了吧。我的记忆方法就是“Pointer to Const”翻译为“常量的指针”，简称“常量指针”；“Const Pointer”翻译为“指针常量”。</p>
<p>最后简单总结一下跟const相关的变量的写法：</p>
<pre><div class="codecolorer-container cpp geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">int</span> a <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span> b <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #666666;">// An int that cannot be changed.</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> constNumber_1 <span style="color: #000080;">=</span> a<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span> <span style="color: #0000ff;">const</span> constNumber_2 <span style="color: #000080;">=</span> a<span style="color: #008080;">;</span><br />
<span style="color: #666666;">//constNumber_1 = 10;</span><br />
<br />
<span style="color: #666666;">// A pointer that can be repointed to an int that cannot be changed.</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span><span style="color: #000040;">*</span> pointerToConst_1 <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>a<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span> <span style="color: #0000ff;">const</span><span style="color: #000040;">*</span> pointerToConst_2 <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>a<span style="color: #008080;">;</span><br />
pointerToConst_1 <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>b<span style="color: #008080;">;</span><br />
<span style="color: #666666;">//*pointerToConst_1 = 10;</span><br />
<br />
<span style="color: #666666;">// A pointer that cannot be moved to an integer that may be changed.</span><br />
<span style="color: #0000ff;">int</span><span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span> constPointer <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>a<span style="color: #008080;">;</span><br />
<span style="color: #666666;">//constPointer = &amp;b;</span><br />
<span style="color: #000040;">*</span>constPointer <span style="color: #000080;">=</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #666666;">// A pointer that cannot be moved to an integer that cannot be changed.</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span><span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span> constPointerToConst_1 <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>a<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span> <span style="color: #0000ff;">const</span><span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span> constPointerToConst_2 <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>a<span style="color: #008080;">;</span><br />
<span style="color: #666666;">//constPointerToConst_1 = &amp;b;</span><br />
<span style="color: #666666;">//*constPointerToConst_1 = 10;</span><br />
<br />
<span style="color: #666666;">// Error, const applied to int twice.</span><br />
<span style="color: #666666;">// (warning C4114: same type qualifier used more than once).</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> <span style="color: #0000ff;">const</span><span style="color: #000040;">*</span> pointerToTwiceConst <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>a<span style="color: #008080;">;</span><br />
pointerToTwiceConst <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>b<span style="color: #008080;">;</span><br />
<span style="color: #666666;">//*pointerToTwiceConst = 10;</span><br />
<br />
<span style="color: #666666;">// A pointer that may be repointed. It points to a pointer that cannot be moved to</span><br />
<span style="color: #666666;">// an int that may be modified.</span><br />
<span style="color: #0000ff;">int</span><span style="color: #000040;">*</span> pa <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>a<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span><span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span><span style="color: #000040;">*</span> pointerToConstPointer <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>pa<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">int</span><span style="color: #000040;">*</span> pb <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>b<span style="color: #008080;">;</span><br />
pointerToConstPointer <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>pb<span style="color: #008080;">;</span><br />
<span style="color: #666666;">//*pointerToConstPointer = pb;</span><br />
<span style="color: #000040;">**</span>pointerToConstPointer <span style="color: #000080;">=</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div></pre>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/cpp-singleton.html' rel='bookmark' title='可以继承的C++ Singleton基类'>可以继承的C++ Singleton基类</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/cpp-const-and-pointer.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>利用等概率Rand5产生等概率Rand3</title>
		<link>http://www.gocalf.com/blog/build-rank3-from-rand5.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=build-rank3-from-rand5</link>
		<comments>http://www.gocalf.com/blog/build-rank3-from-rand5.html#comments</comments>
		<pubDate>Tue, 02 Aug 2011 15:10:18 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[极限]]></category>
		<category><![CDATA[概率]]></category>
		<category><![CDATA[等概率]]></category>
		<category><![CDATA[算法题]]></category>
		<category><![CDATA[随机数]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=865</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/dice_5.png" class="attachment-post-thumbnail wp-post-image" alt="dice_5" title="dice_5" /></div>问题描述：现在有一个叫做Rand5的函数，可以生成等概率的[0, 5)范围内的随机整数，要求利用此函数写一个Rand3函数（除此之外，不能再使用任何能产生随机数的函数或数据源），生成等概率的[0, 3)范围内的随机整数。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/08/dice_5.png" class="attachment-post-thumbnail wp-post-image" alt="dice_5" title="dice_5" /></div><p>问题本身很明确，但不知道起个什么题目好，姑且先这么说吧。</p>
<p>问题描述：现在有一个叫做Rand5的函数，可以生成等概率的[0, 5)范围内的随机整数，要求利用此函数写一个Rand3函数（除此之外，不能再使用任何能产生随机数的函数或数据源），生成等概率的[0, 3)范围内的随机整数。<span id="more-865"></span></p>
<p>我第一次遇到这个问题的时候，着实犯了一回傻，自以为是地证明了这个题目是无解的。其实从概率的角度来看，题目的要求就是，利用一个1/5的概率源，通过某种方式产生出1/3的概率输出。我们都知道，概率运算法则有加法和乘法，而在我的记忆中，算法是“在有限步骤内求解某一问题所使用的一组定义明确的规则”，算法的一个重要特征就是有穷性，即一个算法必须保证执行有限步之后结束。那么有限多个1/5通过加法和乘法是不可能的到1/3这个数值的，因为加法和乘法都不会给分母带来新的因子，那么分母中的3根本就不可能出现。</p>
<p>然而我忽略了这样一个式子：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_21b6d5da4ee9676d6f70b89b36cabf06.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\sum_{i=0}^\infty \left(\frac{2}{5}\right)^i = \frac{1}{1-\frac{2}{5}} = \frac{5}{3}" title="\sum_{i=0}^\infty \left(\frac{2}{5}\right)^i = \frac{1}{1-\frac{2}{5}} = \frac{5}{3}" /></span><script type='math/tex'>\sum_{i=0}^\infty \left(\frac{2}{5}\right)^i = \frac{1}{1-\frac{2}{5}} = \frac{5}{3}</script></p>
<p>基于这个想法，我们来看看这个算法是什么样子的：</p>
<div id="wp-tabs-8" class="wp-tabs wpui-light wpui-styles"><h3 class="wp-tab-title">Python</h3></p>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> Rand3<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; x <span style="color: #66cc66;">=</span> -<span style="color: #ff4500;">1</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff4500;">0</span> <span style="color: #66cc66;">&lt;=</span> x <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">3</span>:<br />
&nbsp; &nbsp; x <span style="color: #66cc66;">=</span> Rand5<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> x</div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<p><h3 class="wp-tab-title">C++</h3></p>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container cpp geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">int</span> Rand3<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">int</span> x<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">do</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; x <span style="color: #000080;">=</span> Rand5<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>x <span style="color: #000080;">&gt;=</span> <span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">return</span> x<span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<p></div><!-- end div.wp-tabs -->
<p>算法很简单，x是我们最终要输出的数字，只要它不在[0, 3)范围内，就不断地调用Rand5来更新它。直观地看，算法输出的数字只有0、1、2这三个，而且对任何一个都没有偏袒，那么显然每个数字的概率都是1/3，那让我们来严格地计算一下。</p>
<p>以输出0为例，看看概率是多少。x的第一个有效数值是通过Rand5得到的。Rand5返回0的概率是1/5，如果这事儿发生了，我们就得到了0，否则只有当Rand5返回3或4的时候，我们才有机会再次调用它来得到新的数据。第二次调用Rand5之后，又是有1/5的概率得到0，2/5的概率得到3或4导致循环继续执行下去，如此反复。因此概率的计算公式为：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_1305088e8ac56b65dd462249e613b17a.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{array}{rcl} p & = & \frac{1}{5}+\frac{2}{5}\times\left(\frac{1}{5}+\frac{2}{5}\times\left(\frac{1}{5}+\frac{2}{5}\times\left(\cdots\right)\right)\right) \\ & = & \frac{1}{5}\times\sum_{i=0}^\infty \left(\frac{2}{5}\right)^i \\ & = & \frac{1}{5}\times\frac{1}{1-\frac{2}{5}} \\ & = & \frac{1}{5}\times\frac{5}{3} \\ & = & \frac{1}{3} \end{array}" title="\begin{array}{rcl} p & = & \frac{1}{5}+\frac{2}{5}\times\left(\frac{1}{5}+\frac{2}{5}\times\left(\frac{1}{5}+\frac{2}{5}\times\left(\cdots\right)\right)\right) \\ & = & \frac{1}{5}\times\sum_{i=0}^\infty \left(\frac{2}{5}\right)^i \\ & = & \frac{1}{5}\times\frac{1}{1-\frac{2}{5}} \\ & = & \frac{1}{5}\times\frac{5}{3} \\ & = & \frac{1}{3} \end{array}" /></span><script type='math/tex'>\begin{array}{rcl} p & = & \frac{1}{5}+\frac{2}{5}\times\left(\frac{1}{5}+\frac{2}{5}\times\left(\frac{1}{5}+\frac{2}{5}\times\left(\cdots\right)\right)\right) \\ & = & \frac{1}{5}\times\sum_{i=0}^\infty \left(\frac{2}{5}\right)^i \\ & = & \frac{1}{5}\times\frac{1}{1-\frac{2}{5}} \\ & = & \frac{1}{5}\times\frac{5}{3} \\ & = & \frac{1}{3} \end{array}</script></p>
<p>喏，计算表明，Rand3输出0的概率确实是1/3，对于另外两个数字也是一样的。</p>
<p>那么这段代码是不是一个算法呢，它是否满足算法的有穷性呢？我不能确定，虽然它不停机的概率是0，然而这个概率是一个极限值，唉，回去复习极限知识先。</p>
<p>改变一下题目，如果要求利用Rand5编写Rand7怎么办？很简单，用两个Rand5可以拼出Rand25，然后就用前面的方法即可：</p>
<div id="wp-tabs-9" class="wp-tabs wpui-light wpui-styles"><h3 class="wp-tab-title">Python</h3></p>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> Rand7<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; x <span style="color: #66cc66;">=</span> -<span style="color: #ff4500;">1</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff4500;">0</span> <span style="color: #66cc66;">&lt;=</span> x <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">21</span>:<br />
&nbsp; &nbsp; x <span style="color: #66cc66;">=</span> Rand5<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> * <span style="color: #ff4500;">5</span> + Rand5<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> x % <span style="color: #ff4500;">7</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<p><h3 class="wp-tab-title">C++</h3></p>
<pre><div class="wp-tab-content"><div class="wp-tab-content-wrapper"><div class="codecolorer-container cpp geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">int</span> Rand7<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">int</span> x<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">do</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; x <span style="color: #000080;">=</span> Rand5<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">*</span> <span style="color: #0000dd;">5</span> <span style="color: #000040;">+</span> Rand5<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>x <span style="color: #000080;">&gt;=</span> <span style="color: #0000dd;">21</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">return</span> x <span style="color: #000040;">%</span> <span style="color: #0000dd;">7</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div></div></div><!-- end div.wp-tab-content --></pre>
<p></div><!-- end div.wp-tabs -->
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/circularly-ordinal-array.html' rel='bookmark' title='在循环有序数组中查找指定元素'>在循环有序数组中查找指定元素</a></li>
<li><a href='http://www.gocalf.com/blog/random-selection.html' rel='bookmark' title='单次遍历，等概率随机选取问题'>单次遍历，等概率随机选取问题</a></li>
<li><a href='http://www.gocalf.com/blog/shuffle-algo.html' rel='bookmark' title='等概率随机排列数组（洗牌算法）'>等概率随机排列数组（洗牌算法）</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection-2.html' rel='bookmark' title='单次遍历，带权随机选取问题（二）'>单次遍历，带权随机选取问题（二）</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/build-rank3-from-rand5.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<series:name><![CDATA[常见面试算法题]]></series:name>
	</item>
		<item>
		<title>解决BlueHost邮箱无法接收邮件的问题</title>
		<link>http://www.gocalf.com/blog/bluehost-mailbox.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=bluehost-mailbox</link>
		<comments>http://www.gocalf.com/blog/bluehost-mailbox.html#comments</comments>
		<pubDate>Sun, 31 Jul 2011 14:04:34 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[建站]]></category>
		<category><![CDATA[A记录]]></category>
		<category><![CDATA[BlueHost]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[GoDaddy]]></category>
		<category><![CDATA[Hosting]]></category>
		<category><![CDATA[Mail Exchanger]]></category>
		<category><![CDATA[MX]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=856</guid>
		<description><![CDATA[<div style="float:left;"><img width="53" height="45" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/webmail.png" class="attachment-post-thumbnail wp-post-image" alt="webmail" title="webmail" /></div>在之前的一篇文章中提到GoCalf网站的Email部分还没弄好，当时遇到的问题是可以发出邮件，却无法接收邮件。问题根源在于DNS没有设置好（空间跟域名来自不同的提供商），今天花了一点儿时间把这个问题解决了。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="53" height="45" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/webmail.png" class="attachment-post-thumbnail wp-post-image" alt="webmail" title="webmail" /></div><p>在之前的<a href="http://www.gocalf.com/blog/lets-start.html" title="GoCalf 建站的初始步骤">一篇文章</a>中提到<a href="http://www.gocalf.com/" target="_blank" title="GoCalf">GoCalf</a>网站的Email部分还没弄好，当时遇到的问题是可以发出邮件，却无法接收邮件。问题根源在于DNS没有设置好（空间跟域名来自不同的提供商），今天花了一点儿时间把这个问题解决了。<span id="more-856"></span></p>
<p>我的域名是<a href="http://www.godaddy.com" target="_blank" title="GoDaddy">GoDaddy</a>提供的，而服务器空间则在<a href="http://www.bluehost.com/" target="_blank" title="BlueHost">BlueHost</a>上，域名解析（DNS）是在GoDaddy上进行的。之前已经将二级域名mail的A记录指向GoCalf空间的IP地址了，可以登录邮箱，能发出邮件，但怎么都收不到信。在Gmail（或别的邮件服务器）中给BlueHost上的邮件帐户发邮件，会收到无法送达的失败提示：</p>
<blockquote>Delivery to the following recipient failed permanently:<br />
&nbsp; &nbsp; xxx@xxxxxxxx.com<br />
Technical details of permanent failure:<br />
Google tried to deliver your message, but it was rejected by the recipient domain. We recommend contacting the other email provider for further information about the cause of this error. The error that the other server returned was: 550 550 #5.1.0 Address rejected xxx@xxxxxxxx.com (state 14).</blockquote>
<p>看起来应该是DNS的问题（跨服务商就是这点比较麻烦啊）。仔细察看了GoDaddy上DNS Manager里面的内容，发现Mail Exchanger（MX）的配置内容有问题，并没有指向GoCalf的空间地址，因此将MX记录改为指向mail.gocalf.com。改动大概需要一个小时才能生效，生效之后再次发送邮件就可以在BlueHost里收到了。</p>
<p>附GoDaddy里面DNS设置截图：</p>
<div id="attachment_858" class="wp-caption alignnone" style="width: 520px"><img alt="GoDaddy中DNS设置" class="size-full wp-image-858" height="301" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/godaddy_dns.png" title="godaddy_dns" width="510" /><p class="wp-caption-text">将二级域名mail指向@地址；MX记录指向mail.&lt;yourdomain&gt;.com</p></div>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/lets-start.html' rel='bookmark' title='要不就先开始吧'>要不就先开始吧</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/bluehost-mailbox.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>关于安装MathJax后占用文件过多的问题</title>
		<link>http://www.gocalf.com/blog/mathjax-numerous-files.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mathjax-numerous-files</link>
		<comments>http://www.gocalf.com/blog/mathjax-numerous-files.html#comments</comments>
		<pubDate>Thu, 28 Jul 2011 14:39:18 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[建站]]></category>
		<category><![CDATA[BlueHost]]></category>
		<category><![CDATA[LaTeX]]></category>
		<category><![CDATA[MathJax]]></category>
		<category><![CDATA[Web Font]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=852</guid>
		<description><![CDATA[<div style="float:left;"><img width="171" height="105" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/jax.png" class="attachment-post-thumbnail wp-post-image" alt="jax" title="jax" /></div>MathJax在安装目录下有三万多个文件，百分之九十九以上都是由图片字体[cci]mathjax/fonts/HTML-CSS/TeX/png[/cci]贡献的，这些图片是为不支持的Web Font的浏览器准备的。如果太多的文件影响到服务器空间，可以按照本文的方法删掉以节省空间，减少文件总数。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="171" height="105" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/jax.png" class="attachment-post-thumbnail wp-post-image" alt="jax" title="jax" /></div><p>在<a href="http://www.gocalf.com/blog/latex-wordpress.html" title="WordPress数学公式插件LaTeX">WordPress数学公式插件LaTeX</a>中介绍了GoCalf博客中使用的LaTeX插件，是Zhiqiang开发的<a href="http://wordpress.org/extend/plugins/latex/" target="_blank" title="LaTeX for WordPress">LaTeX for WordPress</a>插件。这个插件利用MathJax来渲染LaTeX公式，效果非常好，后来我在自己的空间里安装了MathJax引擎。可是前两天发现我的空间里竟然有五万多个文件，几乎就要收到BlueHost的警告了，查看了一下文件分布，发现光MathJax就有三万多个文件！怎么能减少文件数目呢？<span id="more-852"></span></p>
<p>对MathJax的安装路径扫描了一下，发现<code class="codecolorer text geshi"><span class="text">mathjax/fonts/HTML-CSS/TeX/png</span></code>下面有无数的小文件，都是图片，每个图片是一个字符。非常奇怪，MathJax不是用JavaScript、CSS和Web Font来显示公式么，怎么会有这么多图片格式的字符。</p>
<p>带着这个疑问到MathJax官方网站上看了看，果然找到了这样一个FAQ：<a href="http://www.mathjax.org/resources/faqs/#fonts-too-big" target="_blank" title="The MathJax font folder is too big. Is there any way to compress it?">The MathJax font folder is too big. Is there any way to compress it?</a></p>
<p>原来这些图片格式的字符是为了让那些古老的不支持Web Font的浏览器也可以正常地显示LaTeX公式，好吧，可怕的向下兼容。在MathJax将其改进之前，我决定先删掉这些图片。先要关闭这种图片字体的功能，直接修改插件的源代码<code class="codecolorer text geshi"><span class="text">blog/wp-content/plugins/latex/latex.php</span></code>，找到关于MathJax配置的代码，修改为：</p>
<pre><div class="codecolorer-container php geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">function</span> add_latex_mathjax_code<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;script type=&quot;text/x-mathjax-config&quot;&gt;</span><br />
<span style="color: #0000ff;"> &nbsp; &nbsp; &nbsp; &nbsp;MathJax.Hub.Config({</span><br />
<span style="color: #0000ff;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;HTML-CSS&quot;: {</span><br />
<span style="color: #0000ff;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;scale: 85,</span><br />
<span style="display:block;background-color:#ffff66"><span style="color: #0000ff;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;imageFont: null</span><br /></span><span style="color: #0000ff;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</span><br />
<span style="color: #0000ff;"> &nbsp; &nbsp; &nbsp; &nbsp;});&lt;/script&gt;</span><br />
<span style="color: #0000ff;"> &nbsp; &nbsp; &nbsp; &nbsp;&lt;script type=&quot;text/javascript&quot; src=&quot;'</span><span style="color: #339933;">.</span>get_option<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;mathjax_server&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&quot;&gt;&lt;/script&gt;'</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div></pre>
<p>其中第6行就是新添加的内容（还有第5行末尾的逗号），这样MathJax就不会再使用图片字体，然后把上面提到的那个目录整个删掉就可以了。当然TeX目录下还有其他几个文件夹，如eot、otf和svg，这些可不要删，要不然在什么浏览器上都无法显示公式了。</p>
<p>试了一下，至少IE6+、Chrome、FireFox、Safari（包括iPhone、iPad版）都可以正常显示公式。</p>
<p>呼，一下子清理掉三万多文件，不错。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/latex-wordpress.html' rel='bookmark' title='WordPress数学公式插件LaTeX'>WordPress数学公式插件LaTeX</a></li>
<li><a href='http://www.gocalf.com/blog/latex-plugin-more.html' rel='bookmark' title='关于LaTeX插件再啰嗦几句'>关于LaTeX插件再啰嗦几句</a></li>
<li><a href='http://www.gocalf.com/blog/wordpress-latex-old.html' rel='bookmark' title='为你的WordPress站点添加LaTeX支持'>为你的WordPress站点添加LaTeX支持</a></li>
<li><a href='http://www.gocalf.com/blog/google-doodle-calder.html' rel='bookmark' title='今日Google图标：动态雕塑家Calder诞辰113周年'>今日Google图标：动态雕塑家Calder诞辰113周年</a></li>
<li><a href='http://www.gocalf.com/blog/puzzle-wwwdot-google-dotcom.html' rel='bookmark' title='数学趣题WWWDOT-GOOGLE=DOTCOM'>数学趣题WWWDOT-GOOGLE=DOTCOM</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/mathjax-numerous-files.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>纸张的尺寸：A、B、C号纸，纸张开本</title>
		<link>http://www.gocalf.com/blog/about-paper-size.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=about-paper-size</link>
		<comments>http://www.gocalf.com/blog/about-paper-size.html#comments</comments>
		<pubDate>Wed, 27 Jul 2011 14:11:03 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[有用知识]]></category>
		<category><![CDATA[A4纸]]></category>
		<category><![CDATA[ISO标准]]></category>
		<category><![CDATA[开本]]></category>
		<category><![CDATA[纸张]]></category>
		<category><![CDATA[纸张大小]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=846</guid>
		<description><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/paper.png" class="attachment-post-thumbnail wp-post-image" alt="paper" title="paper" /></div>小时候常说的16开、32开的纸是多大？现在打印复印用的A3、A4、B5纸又分别是多大？看到书架里高矮宽窄各不同的书本，赶紧上网查了一番，总结于此。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="128" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/paper.png" class="attachment-post-thumbnail wp-post-image" alt="paper" title="paper" /></div><p>记得小时候买书本，都会提到多少多少开，成语词典好像是64开，小学课本是32开，到高中教材改革，课本变成了16开。随着打印机、复印机的广泛应用，现在似乎很少说多少开了，张口就是A4纸，A3纸，还有B5、C5之类的。它们的尺寸分别是多少？大小关系呢？</p>
<p>看到书架里高矮宽窄各不同的书本，赶紧上网查了一番，总结于此。<span id="more-846"></span></p>
<p>先说现在的复印纸。有A、B、C三个系列，它们的尺寸遵循国际标准<a href="http://en.wikipedia.org/wiki/A4_paper" target="_blank" title="ISO 216">ISO 216</a>和<a href="http://en.wikipedia.org/wiki/ISO_269" target="_blank" title="ISO 269">ISO 269</a>。</p>
<p>A系列从A0开始，这是一整张纸，将其沿长边对折，每半都是A1，继续沿长边对折得到A2，以此类推。由于每次对折之后，纸张的长宽比保持不变，可知（a、b分别代表短边、长边）<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_fdd4555a9b39d6a2d513458705c1bda3.gif' style='vertical-align: middle; border: none; ' class='tex' alt="a:b=\frac{b}{2}:a\Rightarrow a:b=1:\sqrt2" title="a:b=\frac{b}{2}:a\Rightarrow a:b=1:\sqrt2" /></span><script type='math/tex'>a:b=\frac{b}{2}:a\Rightarrow a:b=1:\sqrt2</script>。A0的面积是<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_1f66a358857c8d46fb953cb3f4e235f5.gif' style='vertical-align: middle; border: none; ' class='tex' alt="1m^2" title="1m^2" /></span><script type='math/tex'>1m^2</script>，由此可以推算出其尺寸为841 x 1189（单位是毫米，下同）：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_9029f8a706778dbf27e380575793c8de.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\left\{\begin{matrix} \sqrt{10^6/\sqrt2}\approx 841\\ \sqrt2\sqrt{10^6/\sqrt2}\approx 1189 \end{matrix} \right." title="\left\{\begin{matrix} \sqrt{10^6/\sqrt2}\approx 841\\ \sqrt2\sqrt{10^6/\sqrt2}\approx 1189 \end{matrix} \right." /></span><script type='math/tex'>\left\{\begin{matrix} \sqrt{10^6/\sqrt2}\approx 841\\ \sqrt2\sqrt{10^6/\sqrt2}\approx 1189 \end{matrix} \right.</script></p>
<p>将A0纸张长边减半，就可以得到A1的尺寸（不能整除时下取整），为594 x 841。常用的A3纸是297 x 420，A4纸是210 x 297。维基百科上还给出了边长的通项公式：纸张An的尺寸是<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_d4a7df989f97685bdcba0d418a57b57d.gif' style='vertical-align: middle; border: none; ' class='tex' alt="a_n \times a_{n+1}" title="a_n \times a_{n+1}" /></span><script type='math/tex'>a_n \times a_{n+1}</script>，其中<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_24ab2c6d388e571c820280fc00a1248b.gif' style='vertical-align: middle; border: none; ' class='tex' alt="a_n=\left \lfloor 1000\times 2^{1/4-n/2}+0.2 \right \rfloor" title="a_n=\left \lfloor 1000\times 2^{1/4-n/2}+0.2 \right \rfloor" /></span><script type='math/tex'>a_n=\left \lfloor 1000\times 2^{1/4-n/2}+0.2 \right \rfloor</script>，是一个等比数列（这里加0.2下取整是使得A0的面积尽可能接近一平米，其他编号的纸张面积最接近但不超过前一编号纸张的一半）。</p>
<p>B系列的尺寸被定义为相同编号的A系列纸张，与前一编号的A系列纸张的几何平均（乘积的开方）。即B1的尺寸是A1和A0的几何平均。直接根据A0的通项公式可以得到：纸张Bn的尺寸是<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_41d5c2de0945c7c505af92a0209f0821.gif' style='vertical-align: middle; border: none; ' class='tex' alt="b_n \times b_{n+1}" title="b_n \times b_{n+1}" /></span><script type='math/tex'>b_n \times b_{n+1}</script>，其中<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_01abcb930ef06b81858d082951f3eace.gif' style='vertical-align: middle; border: none; ' class='tex' alt="b_n=\left \lfloor 1000\times 2^{1/2-n/2}+0.2 \right \rfloor" title="b_n=\left \lfloor 1000\times 2^{1/2-n/2}+0.2 \right \rfloor" /></span><script type='math/tex'>b_n=\left \lfloor 1000\times 2^{1/2-n/2}+0.2 \right \rfloor</script>。可见B纸的边长是相同编号的A纸的<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_2f92f26b5ec4b063312e1be4bafd7452.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\sqrt[4]{2}" title="\sqrt[4]{2}" /></span><script type='math/tex'>\sqrt[4]{2}</script>倍，面积是<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_dbf970b20271ad58feed105bf88fd19f.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="\sqrt2" title="\sqrt2" /></span><script type='math/tex'>\sqrt2</script>倍。B0的尺寸是1000x1414，B4是250x353。</p>
<p>C系列是信封系列，其尺寸是相同编号的A纸与B纸的几何平均。可以推算出其通项公式为：<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_9bbb852e0d6da476995ed5e3cae25411.gif' style='vertical-align: middle; border: none; ' class='tex' alt="c_n=\left \lfloor 1000\times 2^{3/8-n/2}+0.2 \right \rfloor" title="c_n=\left \lfloor 1000\times 2^{3/8-n/2}+0.2 \right \rfloor" /></span><script type='math/tex'>c_n=\left \lfloor 1000\times 2^{3/8-n/2}+0.2 \right \rfloor</script>。C0的尺寸是917 x 1297，C4为229 x 324。C4刚好比A4大一点儿，正好可以给A4纸当信封。</p>
<p>下面这个表列出了A、B、C三个系列纸张的尺寸：</p>
<table>
<thead>
<tr>
<th colspan="2">A系列</th>
<th colspan="2">B系列</th>
<th colspan="2">C系列</th>
</tr>
</thead>
<tbody>
<tr>
<td>A0</td>
<td>841 x 1189</td>
<td>B0</td>
<td>1000 x 1414</td>
<td>C0</td>
<td>917 x 1297</td>
</tr>
<tr>
<td>A1</td>
<td>594 x 841</td>
<td>B1</td>
<td>707 x 1000</td>
<td>C1</td>
<td>648 x 917</td>
</tr>
<tr>
<td>A2</td>
<td>420 x 594</td>
<td>B2</td>
<td>500 x 707</td>
<td>C2</td>
<td>458 x 648</td>
</tr>
<tr>
<td>A3</td>
<td>297 x 420</td>
<td>B3</td>
<td>353 x 500</td>
<td>C3</td>
<td>324 x 458</td>
</tr>
<tr>
<td>A4</td>
<td>210 x 297</td>
<td>B4</td>
<td>250 x 353</td>
<td>C4</td>
<td>229 x 324</td>
</tr>
<tr>
<td>A5</td>
<td>148 x 210</td>
<td>B5</td>
<td>176 x 250</td>
<td>C5</td>
<td>162 x 229</td>
</tr>
<tr>
<td>A6</td>
<td>105 x 148</td>
<td>B6</td>
<td>125 x 176</td>
<td>C6</td>
<td>114 x 162</td>
</tr>
<tr>
<td>A7</td>
<td>74 x 105</td>
<td>B7</td>
<td>88 x 125</td>
<td>C7</td>
<td>81 x 114</td>
</tr>
<tr>
<td>A8</td>
<td>52 x 74</td>
<td>B8</td>
<td>62 x 88</td>
<td>C8</td>
<td>57 x 81</td>
</tr>
<tr>
<td>A9</td>
<td>37 x 52</td>
<td>B9</td>
<td>44 x 62</td>
<td>C9</td>
<td>40 x 57</td>
</tr>
<tr>
<td>A10</td>
<td>26 x 37</td>
<td>B10</td>
<td>31 x 44</td>
<td>C10</td>
<td>28 x 40</td>
</tr>
</tbody>
</table>
<p>本来想下载ISO 216标准完整版阅读一下，没想到很贵呢，要<a href="http://webstore.ansi.org/RecordDetail.aspx?sku=ISO+216%3a2007" target="_blank" title="购买ISO 216标准">七十多美元</a>。</p>
<p>再来看小时候常说的开本，什么16开、32开。其实很容易理解啦，16开就是把一张大纸裁成16等份（对折4次，类似于A4），32开就是把16开纸再对折1次（类似于A5）。而整张的大纸的尺寸在我国也有好几种，最常见的有（宽长比差不多都是<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_cfa97eece8fc5e7e9d9a1e2b3b16ad38.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="1:\sqrt2" title="1:\sqrt2" /></span><script type='math/tex'>1:\sqrt2</script>）：</p>
<ul>
<li>787号纸（正度纸）：787 x 1092</li>
<li>850号纸（大度纸）：850 x 1168</li>
<li>880号纸：880 x 1230</li>
<li>889号纸（也有说这个是大度纸，搞不清楚）：889 x 1194</li>
</ul>
<p>不过如果按照对折的办法去算开纸的尺寸，比如787号纸的16开是196 x 273，这个尺寸一般要比16开的书大，因为书籍还要修边裁剪啥的。比如我手边的交规课本就是787号纸16开的，实际尺寸是186 x 259。除了常见的对开（就是2开）、4开、8开、16开、32开、64开（袖珍手册），偶尔也能看到其他开本。比如我手边有一本讲PPT的书是889号纸24开的，实际尺寸是180 x 210，貌似是把4开本沿短边对折后再沿长边三折：</p>
<div id="attachment_851" class="wp-caption alignnone" style="width: 245px"><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/07/paper_24k.png" target="_blank"><img alt="889 x 1194 24开本" class="size-medium wp-image-851 " height="300" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/paper_24k-235x300.png" title="paper_24k" width="235" /></a><p class="wp-caption-text">889 x 1194 24开本</p></div>
<p>对于给定的原始尺寸，可以用下面这段程序（Python）来算出1～10次对折后的尺寸：</p>
<pre><div class="codecolorer-container python geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> Kai<span style="color: black;">&#40;</span>x<span style="color: #66cc66;">,</span> y<span style="color: black;">&#41;</span>:<br />
&nbsp; n <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">11</span><br />
&nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> i<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">':'</span><span style="color: #66cc66;">,</span> x<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'x'</span><span style="color: #66cc66;">,</span> y<br />
&nbsp; &nbsp; x<span style="color: #66cc66;">,</span> y <span style="color: #66cc66;">=</span> y/<span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> x<br />
<br />
Kai<span style="color: black;">&#40;</span><span style="color: #ff4500;">841</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1189</span><span style="color: black;">&#41;</span></div></div></pre>
<p>下面的表格列出了这四种纸张各个开本的未修边尺寸（有些格子里列出了常见的修边后的尺寸）：</p>
<table>
<thead>
<tr>
<th>开本</th>
<th>787号纸</th>
<th>850号纸</th>
<th>880号纸</th>
<th>889号纸</th>
</tr>
</thead>
<tbody>
<tr>
<td>全张</td>
<td>787 x 1092</td>
<td>850 x 1168</td>
<td>880 x 1230</td>
<td>889 x 1194</td>
</tr>
<tr>
<td>2开</td>
<td>546 x 787</td>
<td>584 x 850</td>
<td>615 x 880</td>
<td>597 x 889</td>
</tr>
<tr>
<td>4开</td>
<td>393 x 546</td>
<td>425 x 584</td>
<td>440 x 615</td>
<td>444 x 597</td>
</tr>
<tr>
<td>8开</td>
<td>273 x 393<br />
(260 x 368)</td>
<td>292 x 425<br />
(285 x 420)</td>
<td>307 x 440</td>
<td>298 x 444</td>
</tr>
<tr>
<td>16开</td>
<td>196 x 273<br />
(184 x 260)</td>
<td>212 x 292<br />
(210 x 285)</td>
<td>220 x 307</td>
<td>222 x 298</td>
</tr>
<tr>
<td>32开</td>
<td>136 x 196<br />
(130 x 184)</td>
<td>146 x 212<br />
(140 x 203)</td>
<td>153 x 220</td>
<td>149 x 222</td>
</tr>
<tr>
<td>64开</td>
<td>98 x 136</td>
<td>106 x 146</td>
<td>110 x 153</td>
<td>111 x 149</td>
</tr>
<tr>
<td>128开</td>
<td>68 x 98</td>
<td>73 x 106</td>
<td>76 x 110</td>
<td>74 x 111</td>
</tr>
</tbody>
</table>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/calendar-of-week.html' rel='bookmark' title='星期万年历'>星期万年历</a></li>
<li><a href='http://www.gocalf.com/blog/build-rank3-from-rand5.html' rel='bookmark' title='利用等概率Rand5产生等概率Rand3'>利用等概率Rand5产生等概率Rand3</a></li>
<li><a href='http://www.gocalf.com/blog/weighted-random-selection.html' rel='bookmark' title='单次遍历，带权随机选取问题（一）'>单次遍历，带权随机选取问题（一）</a></li>
<li><a href='http://www.gocalf.com/blog/circularly-ordinal-array.html' rel='bookmark' title='在循环有序数组中查找指定元素'>在循环有序数组中查找指定元素</a></li>
<li><a href='http://www.gocalf.com/blog/latex-wordpress.html' rel='bookmark' title='WordPress数学公式插件LaTeX'>WordPress数学公式插件LaTeX</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/about-paper-size.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dell E6400安装MacOS雪豹10.6</title>
		<link>http://www.gocalf.com/blog/dell-e6400-install-mac.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=dell-e6400-install-mac</link>
		<comments>http://www.gocalf.com/blog/dell-e6400-install-mac.html#comments</comments>
		<pubDate>Sun, 24 Jul 2011 10:08:32 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[操作系统]]></category>
		<category><![CDATA[BootThink]]></category>
		<category><![CDATA[Dell E6400]]></category>
		<category><![CDATA[Hackintosh]]></category>
		<category><![CDATA[MacOS]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[PC]]></category>
		<category><![CDATA[PC机装Mac]]></category>
		<category><![CDATA[雪豹]]></category>
		<category><![CDATA[黑苹果]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=834</guid>
		<description><![CDATA[<div style="float:left;"><img width="134" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/mac_os_x.png" class="attachment-post-thumbnail wp-post-image" alt="mac_os_x" title="mac_os_x" /></div>半年前在Dell Latitude E6400上安装了Mac OS X Snow Leopard 10.6（与Windows 7并存），除了WiFi之外都挺好的，折腾了好久才搞定，现在又有些记不清了，所以要赶紧留下印记，以免过几天就忘光了。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="134" height="128" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/mac_os_x.png" class="attachment-post-thumbnail wp-post-image" alt="mac_os_x" title="mac_os_x" /></div><p>半年前在Dell Latitude E6400上安装了Mac OS X Snow Leopard 10.6（与Windows 7并存），除了WiFi之外都挺好的，折腾了好久才搞定，现在又有些记不清了，所以要赶紧留下印记，以免过几天就忘光了。</p>
<p>不知道为什么，这次装10.6非常的费劲，尝试了好几个不同的版本（包括原版、iAntares、精简版等等），尝试了光盘安装、硬盘安装，尝试了BootThink引导、变色龙引导，用了一周多的时间才搞成功。相比之下，之前装10.5.5～10.5.7都非常容易呢。</p>
<p>在PC上装Mac的教程满天飞，这里不打算详细讲述，就以跟Dell E6400有关的部分和遇到的一些问题为主吧，这款机器似乎是最难装Mac的机器之一。<span id="more-834"></span></p>
<h3>Dell Latitude E6400硬件配置</h3>
<p>为PC装Mac系统最头疼的当然是硬件驱动了，所以在安装前要先搞清楚机器的硬件情况。</p>
<ul>
<li>Chip set
<ul>
<li>North Bridge: Intel Cantiga PM45</li>
<li>Source Bridge:&nbsp;Intel 82801 IEM ICH9M-E</li>
</ul>
</li>
<li>BIOS:&nbsp;Phoenix 05/11/09</li>
<li>CPU:&nbsp;Intel Core2 Duo P9600 2800MHz (10.5 x 267)</li>
<li>Memory:&nbsp;2G*2, 800MHz Dual</li>
<li>Storage: Intel ICH9M-E/M SATA AHCI Controller</li>
<li>Video: nVIDIA Quadro NVS160M (256MB)</li>
<li>Audio: &nbsp;IDT 92HD 71B7 @ Intel 82801 IB ICH9 - High Definition Audio Controller [A-3] PCI</li>
<li>Display: 1440x900</li>
<li>Network
<ul>
<li>Ethernet: Intel 82567LG Gigabit Network Connection</li>
<li>WiFi: Intel WiFi Link 5300 AGN （最让人头疼的硬件，驱动无解）</li>
</ul>
</li>
</ul>
<h3>工具和准备工作</h3>
<p>下载了Mac OS X 10.6原版光盘镜像（尝试了很多其他处理好的镜像，全都无法正常安装，最后还是选择用原版），我用的是snowleopard_10a432_userdvd.dmg（网上到处都能下载，我就不发链接了），6.13G。这么大就不刻盘了，用光盘装还慢呢。</p>
<p>用硬盘安装的话，一般要给磁盘上新建两个分区，一个放安装盘镜像，一个装Mac。前者6.3G左右（不要格式化），后者试个人需要，一般至少20G（NTFS格式）。我用的BootThink引导似乎要求被引导的系统（包括安装镜像和已经装好的系统）在主分区上，但我的硬盘上没有那么多主分区可以用了（一块硬盘最多可以有四个主分区，我已经有了三个，分别是Win 7保留分区，Win 7系统分区，数据分区），因此就把最后一个主分区名额留给了Mac系统，而把安装盘镜像放到了移动硬盘上。同样注意放安装盘镜像的分区不要格式化。</p>
<p>接下来安装HFS-Explorer（v0.21），运行，按Ctrl+O（菜单File-&gt;Load file system from file...），选择下载的安装盘镜像，在弹出的对话框里选择Apple_HFS那项。加载之后点击菜单Tool-&gt;Create disk image...，将生成的文件（.dmg）保存在某个NTFS分区上即可。</p>
<div id="attachment_842" class="wp-caption alignnone" style="width: 297px"><img alt="HFS-Explorer选择Partition" class="size-full wp-image-842" height="133" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/hfs_explorer_hfs.png" title="hfs_explorer_hfs" width="287" /><p class="wp-caption-text">HFS-Explorer选择Partition</p></div>
<p>&nbsp;</p>
<div id="attachment_843" class="wp-caption alignnone" style="width: 550px"><img alt="HFS-Explorer" class="size-full wp-image-843" height="485" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/hfs_explorer_view.png" title="hfs_explorer_view" width="540" /><p class="wp-caption-text">在HFS-Explorer中查看安装盘镜像</p></div>
<p>使用HFS-Explorer把下载的安装盘镜像处理一下生成另外一个镜像，主要有三个作用：</p>
<ul>
<li>有些镜像格式无法被后面用到的安装助手识别，这个工具可以做一次格式转换；</li>
<li>去掉原镜像的写保护，以便稍后替换OSInstall（也可以直接下载一个别人替换过的镜像，那就不用装这个工具了，也可以跳过后面的MacDriver）；</li>
<li>可以对原镜像文件做检验。</li>
</ul>
<p>接下来就要祭出Leopard硬盘安装助手（v0.3）了。它不需要安装，但在Win 7系统中必须以管理员身份运行（右键点击，选择Run as administrator）。载入刚才用HFS-Explorer生成的镜像文件，选择之前分好的6.3G左右未格式化的分区，并去掉三个复选框的勾（在boot.ini中加入tboot；强制加入引导及启动代码；PC_EFI V8）。点击“开始！”按钮，然后耐心等待。当进度条走满，日志中出现“Change partition type to AF: Success”、“All done, have fun!”时就算成功了。</p>
<div id="attachment_844" class="wp-caption alignnone" style="width: 512px"><img alt="Leopard硬盘安装助手" class="size-full wp-image-844" height="568" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/lepoard-inshelper.png" title="lepoard-inshelper" width="502" /><p class="wp-caption-text">Leopard硬盘安装助手</p></div>
<p>接下来要替换OSInstall，这需要安装工具MacDriver（v8.0.4.10），这是个收费软件。装好之后重启系统，就可以进入刚才用硬盘安装助手写入的HFS安装分区了。让Windows显示隐藏文件和系统文件，下载一个PC用的OSInstall，替换掉<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">X:\System\Library\PrivateFrameworks\Install.framework\Frameworks\OSInstall.framework\Versions\A\</div></div>里面的同名文件。这样做的目的是使得Mac可以安装在MBR分区表下（否则Mac只能装在GPT（GUID）分区表下，但Windows默认都是用MBR）。（还是直接下载一个已经替换好了的镜像吧，省的麻烦。）</p>
<p>最后还要装引导程序。以前我用的是变色龙引导程序，但这次总是出错，就改用BootThink了。觉得这个比变色龙还要好些吧。不过如果原有系统是Win 7的话，还稍微有一点儿麻烦，就是Win 7那个令人恶心的保留分区。虽然我们一般都把Win 7装在C盘，但在安装过程中，它会在C盘前面保留一个100MB左右的NTFS分区（卷标一般就叫System Reserved），而这个分区默认是不显示出来的（没有分配盘符）。如果把BootThink装在C盘，那有可能会无法进行引导。所以要把它装在那个保留分区里（幸好它体积不是很大）。在磁盘管理中找到那个保留分区，给它指定一个盘符（我习惯用B），然后把BootThink装在这个分区中。（有人说把C盘标记为活动分区就可以启动BootThink，但我没有成功。）安装之后在目标分区的根目录应该有一个文件夹Darwin和两个文件btldr（系统文件）、btldr.mbr。</p>
<h3>准备驱动程序</h3>
<p>网上那些破解过的Mac安装镜像里面通常都包含了各种驱动程序，在安装的时候选择需要的就可以了，但不知道为什么我这次怎么都装不成功，所以才用了原版的镜像。但原版镜像里没有PC的驱动程序，这就要借助BootThink了。用BootThink引导刚才制作的替换了OSInstall的硬盘安装分区，它就可以从C:\Darwin\System\LibrarySL\Extensions\（我的是B:\）里面加载放在那里的驱动程序和补丁（不同版本的Mac OS对应的目录也不太一样，这里就不多说了）。</p>
<p>驱动的选择至关重要啊，选择的不好，轻则某个硬件不工作，重则四国、五国、风火轮（在系统加载时出现用四国或者五国文字写的提示信息，或者风火轮图标一直转却无法进入系统）。这里列出我选择的驱动和补丁。</p>
<ul>
<li>系统补丁
<ul>
<li>fakesmc.kext：模拟苹果机的SMC，必须的！</li>
<li>NullCPUPowerManagement.kext：禁用电源管理，解决IntelCPUPowerManagement.kext的HPET错误。</li>
<li>OpenHaltRestart.kext：解决重启或关机问题。</li>
<li>OSXRestart.kext：解决重启问题。</li>
<li>PlatformUUID.kext：解决UUID错误。</li>
<li>Disabler.kext：屏蔽不能正常启动的补丁。</li>
<li>IOAHCIBlockStorageInjector.kext：解决本地硬盘图标为橙色的补丁。</li>
</ul>
</li>
<li>Video
<ul>
<li>NVinject.kext</li>
</ul>
</li>
<li>Audio
<ul>
<li>IOAudioFamily.kext</li>
<li>HDAEnabler.kext</li>
<li>VoodooHDA.kext</li>
</ul>
</li>
<li>Ethernet
<ul>
<li>IONetworkingFamily.kext</li>
<li>Intel82566MM.kext</li>
</ul>
</li>
<li>WiFi
<ul>
<li>:-( 我那无解的无线网卡，凑合用了个LegacyAppleAirPortBrcm4311.kext，不五国，也没效果</li>
</ul>
</li>
<li>PS/2（鼠标、键盘、触摸板）
<ul>
<li>ApplePS2Controller.kext（或者VoodoPS2Controller.kext）</li>
<li>AppleACPIPS2Nub.kext</li>
</ul>
</li>
<li>Battery
<ul>
<li>VoodooBattery.kext</li>
</ul>
</li>
<li>Bluetooth
<ul>
<li>DellBluetoothHCI.kext</li>
</ul>
</li>
<li>SD Reader
<ul>
<li>VoodooSDHC.kext</li>
</ul>
</li>
<li>PCMCIA
<ul>
<li>IOPCIFamily.kext</li>
</ul>
</li>
<li>Chip set
<ul>
<li>AHCIPortInjector.kext：可以识别Intel芯片组的AHCI。</li>
</ul>
</li>
<li>风扇
<ul>
<li>IOACPIFamily.kext：解决部分笔记本风扇不正常问题，只支持32位。</li>
</ul>
</li>
<li>还有几个已经不记得是干什么用的了
<ul>
<li>AppleRTC.kext</li>
<li>OSvKernDSPLib.kext</li>
</ul>
</li>
</ul>
<h3>安装</h3>
<p>动手安装之前还要注意几件事情。</p>
<p>首先是Snow Lopard需要SATA硬盘支持，所以要确认BIOS中SATA模式设定为AHCI（默认可能是IRRT）。</p>
<p>BootThink的一些操作：</p>
<ul>
<li>c：Leopard原版光盘启动；</li>
<li>Alt：进入startup manager，选取启动分区；</li>
<li>Shift：安全模式；</li>
<li>Ctrl+V（或-v）：Verbose模式；</li>
<li>Ctrl+S：单用户模式；</li>
<li>#g=WxHxDEPTH（如1440x900x32）：设置分辨率；</li>
<li>#g=~：取消分辨率设置；</li>
<li>-32：以32位模式启动。</li>
</ul>
<p>我的E6400用64位总是有些驱动有问题，只好用32位了。在安装和启动Mac的时候，都要在BootThink里输入-x32，或者修改B:\Darwin\com.apple.Boot.plist，添加Kernel Flags，值为arch=i386。我的此文件内容如下：</p>
<pre><div class="codecolorer-container xml geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #00bbdd;">&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;</span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plist</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dict<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>EthernetBuiltIn<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Yes<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Graphics Mode<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1440x900x32<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>GraphicsEnabler<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>y<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Instant Menu<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>No<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Kernel<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>mach_kernel<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Kernel Flags<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>arch=i386<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Timeout<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>3<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>UHCIreset<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Yes<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>device-properties<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dict<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plist<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div></pre>
<p>好了，重启电脑，进入BootThink引导，选择启动Mac安装盘分区。成功话可以看到苹果图标和风火轮，选择语言，然后就进入安装界面。这时候要对目标分区做格式化，点击菜单“实用工具-&gt;磁盘工具...”，在对话框中选择之前格式化成NTFS的空白分区，将选择模式“Mac OS扩展（日志式）”，填写卷标，点击“抹掉”。成功之后关闭窗口，继续安装，接受软解许可协议，然后就是选择安装组件。有人建议不用选“打印机支持”，太占体积了。选好之后继续，选择刚才格式化好的目标分区，点击安装。</p>
<p>如果是用硬盘安装的话，不用等太久就装好了。装好之后会自动重启，不过由于安装过程中，Windows系统盘的活动分区属性被取消了，如果直接重启将无法进入Windows，可以利用重启前的一点时间处理一下。点击菜单“实用工具-&gt;终端”，用diskutil命令来设置活动分区。</p>
<pre><div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"># diskutil list<br />
... blah blah ...（查看C:\在哪里，比如我的在/dev/disk0分区1）<br />
# fdisk -e /dev/disk0<br />
f 1<br />
w<br />
y<br />
quit</div></div></pre>
<p>重启电脑，进入BootThink，这时候就可以看到安装好的Mac系统分区了，引导它启动即可（如果装的是32位，也没改com.apple.Boot.plist，就需要输入-x32以32位模式启动）。</p>
<p>运气不背的话就可以顺利进入Mac系统了，声音、图像、有线网络、触摸板等全都正常，唯一的遗憾是无线网卡不能使用（也不知道这半年来出了新的驱动没）。可以买个USB/PCMCIA无线网卡，也可以像我一样扯根网线。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/dell-e6400-mac-10-6-8.html' rel='bookmark' title='Dell E6400升级到MacOS 10.6.8'>Dell E6400升级到MacOS 10.6.8</a></li>
<li><a href='http://www.gocalf.com/blog/hackintosh-fix-uuid.html' rel='bookmark' title='解决黑苹果Unable to Determine UUID错误'>解决黑苹果Unable to Determine UUID错误</a></li>
<li><a href='http://www.gocalf.com/blog/win7-god-mode.html' rel='bookmark' title='Windows7上帝模式'>Windows7上帝模式</a></li>
<li><a href='http://www.gocalf.com/blog/iphone-dev-hide-status-bar.html' rel='bookmark' title='iPhone开发：隐藏系统状态栏'>iPhone开发：隐藏系统状态栏</a></li>
<li><a href='http://www.gocalf.com/blog/hide-drive-q.html' rel='bookmark' title='隐藏磁盘分区Q'>隐藏磁盘分区Q</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/dell-e6400-install-mac.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>今日Google图标：动态雕塑家Calder诞辰113周年</title>
		<link>http://www.gocalf.com/blog/google-doodle-calder.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=google-doodle-calder</link>
		<comments>http://www.gocalf.com/blog/google-doodle-calder.html#comments</comments>
		<pubDate>Fri, 22 Jul 2011 10:33:10 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[互联网]]></category>
		<category><![CDATA[Canvas]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Google Doodle]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[动态雕塑]]></category>
		<category><![CDATA[雕塑]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=835</guid>
		<description><![CDATA[<div style="float:left;"><img width="114" height="41" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/calder11-sr.png" class="attachment-post-thumbnail wp-post-image" alt="calder11-sr" title="calder11-sr" /></div>现在Google经常会在它的Doodle中加入各种有趣的元素，今天这个就用到了HTML5的Canvas，在支持HTML5 Canvas的浏览器里，可以看到3D的动态Doodle，还可以拖动哦。为了便于以后查看和保存，我把这个Doodle相关的脚本扒下来，在此留存。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="114" height="41" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/calder11-sr.png" class="attachment-post-thumbnail wp-post-image" alt="calder11-sr" title="calder11-sr" /></div><p>现在Google经常会在它的Doodle中加入各种有趣的元素，今天这个就用到了HTML5的Canvas，在支持HTML5 Canvas的浏览器里，可以看到3D的动态Doodle，还可以拖动哦。为了便于以后查看和保存，我把这个Doodle相关的脚本扒下来，在此留存。<span id="more-835"></span></p>
<p>今天（2011年7月22日）是伟大的动态雕塑发明人亚历山大·考尔德（<a href="http://en.wikipedia.org/wiki/Alexander_Calder" target="_blank" title="Alexander Calder">Alexander Calder</a>）诞辰113周年，Google用它的Doodle为大家在浏览器上展示了Calder的动态雕塑作品?The Star (1960)。原作如下图示。</p>
<div id="attachment_837" class="wp-caption alignnone" style="width: 650px"><img alt="亚历山大·考尔德动态雕塑作品 The Star (1960)" class="size-full wp-image-837" height="426" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/calder_the_star.jpg" title="calder_the_star" width="640" /><p class="wp-caption-text">亚历山大·考尔德动态雕塑作品 The Star (1960)</p></div>
<p>当然我对艺术是一窍不通了，对HTML5 Canvas也一无所知。就像电视上有个广告词：“我们不生产水，我们只是大自然的搬运工”。我今天也只是把这个Doodle从Google主页上搬下来，以满足收藏的欲望。由于没有搜索框，我把雕塑阴影的位置调高了一些。</p>
<p>注意，在IE8或IE6（该淘汰了）中是无法看到Canvas的，只能看到静态的图片，请使用其他浏览器。另外可以点击<a href="http://www.gocalf.com/blog/wp-content/uploads/2011/07/doodle_0722.html" target="_blank">doodle_0722_html</a>在单独的HTML页面中查看（方便下载）。</p>
<div style="width: 460px; height: 320px;"><noscript><style>#calder_hotspot{display: none;} canvas{display: none;}</style></noscript>
<div id="hplogo" style="position: relative; width: 400px"><a href="http://www.google.com/search?q=Alexander+Calder&amp;ct=calder11&amp;oi=ddle" id="calder_hotspot" style="background: #fff; opacity: 0; display: block; height: 50px; outline: none; position: absolute; width: 400px; top: 40px; z-index: 5">&nbsp;</a><canvas height="300" id="calder" style="margin-left: -48px; z-index: 0" width="400"></canvas><canvas height="300" id="calder_shadows" style="margin-left: -48px; position: relative;top: -260px; z-index: -1" width="400">
<p>Your browser doesn't suppot &lt;canvas&gt;, please try other browsers.</p>
</canvas><noscript><p>Please enable script in your browser.</p><a href="http://www.gocalf.com/search?q=Alexander+Calder&#038;ct=calder11&#038;oi=ddle" title="Alexander Calder&#39;s 113th Birthday. Courtesy of Calder Foundation / ARS, NY."><img id="hplogo" src="http://www.google.com/logos/2011/calder11.png" alt="Alexander Calder&#39;s 113th Birthday. Courtesy of Calder Foundation / ARS, NY."></a></noscript><script type="text/jscript" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/doodle_0722.js"></script></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/google-doodle-calder.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>时针，分针，相对运动</title>
		<link>http://www.gocalf.com/blog/clock-hands-relative-motion.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=clock-hands-relative-motion</link>
		<comments>http://www.gocalf.com/blog/clock-hands-relative-motion.html#comments</comments>
		<pubDate>Mon, 18 Jul 2011 13:29:26 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[数学]]></category>
		<category><![CDATA[Clock]]></category>
		<category><![CDATA[Interview Question]]></category>
		<category><![CDATA[Math]]></category>
		<category><![CDATA[Puzzle]]></category>
		<category><![CDATA[Relative Motion]]></category>
		<category><![CDATA[智力题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=830</guid>
		<description><![CDATA[<div style="float:left;"><img width="220" height="100" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/clock_40mins.png" class="attachment-post-thumbnail wp-post-image" alt="clock_40mins" title="clock_40mins" /></div>某人6点多从家出发，出门时时针和分针是110度角，7点前回到家，时针和分针还是110度角。问这人出门多久？ 

本文以这个简单的问题入手，介绍了利用相对运动解决时针、分针相关问题的方法。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="220" height="100" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/clock_40mins.png" class="attachment-post-thumbnail wp-post-image" alt="clock_40mins" title="clock_40mins" /></div><p>注意：本文涉及到的是小学、初中级别的问题，请高智商同学自动绕行。</p>
<p>不知道为什么，我从小就对时钟感觉到头疼，类似于时针、分针在什么时刻重合、什么时候成九十度角之类的问题尤其感到无从下手。今天这篇文章用来纪念懵懂的曾经。</p>
<p>感谢Chunxu同学提供的题目：</p>
<blockquote>
<p>某人6点多从家出发，出门时时针和分针是110度角，7点前回到家，时针和分针还是110度角。问这人出门多久？</p>
</blockquote>
<span id="more-830"></span>
<p>这个问题非常简单，设出门时间是6点x分，回家时间是6点y分，根据时针分针的旋转速度列出方程，联列求解，最后求出y-x便是答案。</p>
<p>然而更简单的方法是借助于相对运动。分针每小时钟转一圈，其转速为6度/分；时针12小时转一圈，转速为0.5度/分。所以相对于时针而言，分针的转速是6 - 0.5 = 5.5度/分。根据题目，出门的时候分针比时针落后（顺时针方向为前方）110度，而回家时超前时针110度，那么相对于时针，分针一共转了220度。因此经过的时间就是220 / 5.5 = 40分钟。</p>
<p>用类似的方法求解时针与分针的重合时刻也是非常简单的。比如问四点到五点之间，分针何时与时针重合。因为四点整的时候分针在时针后面120度，当二者重合时，分针相对于时针旋转了120度，耗时120 / 5.5 = 21分49.09秒。所以重合的时刻是4点21分49.09秒（如下图示）。</p>
<div id="attachment_832" class="wp-caption alignnone" style="width: 110px"><img alt="4点21分49.09秒，时针与分针重合" class="size-full wp-image-832" height="100" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/4h21m49s.gif" title="4h21m49s" width="100" /><p class="wp-caption-text">4:21:49.09，时针与分针重合</p></div>
<p>据说微软也曾经拿时针、分针、秒针当过面试题，这东西确实非常简单，但有时候也确实挺让人头疼的。希望以后不会再被类似的问题困扰。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/clock-hands-relative-motion.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>隐藏磁盘分区Q</title>
		<link>http://www.gocalf.com/blog/hide-drive-q.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=hide-drive-q</link>
		<comments>http://www.gocalf.com/blog/hide-drive-q.html#comments</comments>
		<pubDate>Fri, 15 Jul 2011 15:34:36 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[操作系统]]></category>
		<category><![CDATA[App-V]]></category>
		<category><![CDATA[Hide Disk Drive]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[Registry]]></category>
		<category><![CDATA[SoftGrid]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Windows 7]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=813</guid>
		<description><![CDATA[<div style="float:left;"><img width="78" height="87" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/disk-q.png" class="attachment-post-thumbnail wp-post-image" alt="disk-q" title="disk-q" /></div>本文介绍如果隐藏 Windows 7 中那讨厌的无法访问的磁盘分区 Q。]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="78" height="87" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/disk-q.png" class="attachment-post-thumbnail wp-post-image" alt="disk-q" title="disk-q" /></div><p>在 Windows 7 操作系统中，有些用户可能会在我的电脑（My Computer）中看到一个盘符为&nbsp;<strong>Q</strong> 的本地磁盘分区，在磁盘管理中看不到它，无法访问它，也无法删除它。这个恼人的分区图标虽然不会有什么实际的影响，但似乎总是在眼前晃悠，不得不让人想要立刻干掉它。其实要去掉它是非常容易的，让我们一起来看一下。<span id="more-813"></span></p>
<div id="attachment_815" class="wp-caption alignnone" style="width: 437px"><img alt="无法访问的虚拟磁盘分区Q" class="size-full wp-image-815" height="302" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/disk-q-unaccess.png" title="disk-q-unaccess" width="427" /><p class="wp-caption-text">无法访问的虚拟磁盘分区Q</p></div>
<p>这个磁盘分区Q是 Microsoft Application Virtualization Desktop（App-V）使用的一个虚拟分区，我也不记得是装了什么之后它就出现了。要隐藏它只要以下几个简单的步骤：</p>
<div id="attachment_816" class="wp-caption alignnone" style="width: 622px"><img alt="修改注册表" class="size-full wp-image-816" height="320" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/disk-q-registry.png" title="disk-q-registry" width="612" /><p class="wp-caption-text">修改注册表，添加高亮的两个DWORD值</p></div>
<ol>
<li>按Win+R，输入regedit并回车，打开注册表编辑器；</li>
<li>找到<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer</div></div></li>
<li>在Explorer这个键值下添加如下两个DWORD（32位）值：
<ol>
<li>第一个名为<code class="codecolorer text geshi"><span class="text">NoDrives</span></code>，值为16进制的<code class="codecolorer text geshi"><span class="text">10000</span></code>，也就是十进制的<code class="codecolorer text geshi"><span class="text">65536</span></code>；</li>
<li>第二个名为<code class="codecolorer text geshi"><span class="text">NoViewOnDrive</span></code>，值同样是16进制的<code class="codecolorer text geshi"><span class="text">10000</span></code>；</li>
</ol>
</li>
<li>重启一下explorer即可。</li>
</ol>
<p>再次进入我的电脑，就可以看到那讨厌的Q分区消失了。</p>
<div id="attachment_818" class="wp-caption alignnone" style="width: 300px"><img alt="虚拟分区Q被隐藏" class="size-full wp-image-818" height="187" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/disk-q-hidden.png" title="disk-q-hidden" width="290" /><p class="wp-caption-text">虚拟分区Q被隐藏</p></div>
<p>如果对注册表不是非常熟悉的话，请千万谨慎操作。另外可以参考微软官方文档<a href="http://support.microsoft.com/kb/931626/en-us" target="_blank" title="How to hide and to restrict access to the App-V (SoftGrid) client drive letter">How to hide and to restrict access to the App-V (SoftGrid) client drive letter</a>，这里有更加细致入微的步骤说明，以及其他殊途同归的方法。</p>
<p>有人或许会对上面添加的两个16进制10000感兴趣，为什么是这个数，它有什么特殊含义？其实IT人很容易发现这个数在二进制中就是1后面跟16个零，如果看作bit mask的话，就是从最低位开始的第17位；而Q在字母表中恰好也是第17个字母。所以如果想要隐藏别的分区（Why? :-p），就根据分区盘符的字母顺序修改上述两个16进制数值即可。比如改成16进制的4（bit mask第三位），那C盘就消失了：</p>
<div id="attachment_819" class="wp-caption alignnone" style="width: 418px"><img alt="用16进制4隐藏磁盘分区C" class="size-full wp-image-819" height="336" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/disk-c-hidden.png" title="disk-c-hidden" width="408" /><p class="wp-caption-text">用16进制4隐藏磁盘分区C</p></div>
<p>在微软的Knowledge Base中也提供了类似的隐藏磁盘分区的方法，其中也有详细的磁盘分区盘符与二进制数之间的对应关系，详情请见<a href="http://support.microsoft.com/kb/231289" target="_blank" title="Using Group Policy Objects to hide specified drives">Using Group Policy Objects to hide specified drives</a>。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/win7-god-mode.html' rel='bookmark' title='Windows7上帝模式'>Windows7上帝模式</a></li>
<li><a href='http://www.gocalf.com/blog/check-udisk.html' rel='bookmark' title='U盘检测软件：ChipGenius，MyDiskTest'>U盘检测软件：ChipGenius，MyDiskTest</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-characters.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：角色介绍'>《塞尔达传说：黎明公主》攻略：角色介绍</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-2.html' rel='bookmark' title='2011.5.15我们的婚礼（二）——迎亲篇'>2011.5.15我们的婚礼（二）——迎亲篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-3.html' rel='bookmark' title='2011.5.15我们的婚礼（三）——准备篇'>2011.5.15我们的婚礼（三）——准备篇</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/hide-drive-q.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows7上帝模式</title>
		<link>http://www.gocalf.com/blog/win7-god-mode.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=win7-god-mode</link>
		<comments>http://www.gocalf.com/blog/win7-god-mode.html#comments</comments>
		<pubDate>Thu, 14 Jul 2011 09:48:13 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[操作系统]]></category>
		<category><![CDATA[God Mode]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Windows 7]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=784</guid>
		<description><![CDATA[<div style="float:left;"><img width="85" height="78" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/godmode2.png" class="attachment-post-thumbnail wp-post-image" alt="Win7 God Mode Overview" title="godmode2" /></div>在 Windows 7 里，“上帝”能做什么？ 一个简单的方法就可以调出调整 Windows 7 系统里全部功能的面板，这个小小的技巧可以让你控制你电脑中的一切。 启动“上帝模式”的方法非常简单，随便找个地方建立一个文件夹，将其命名为GodMode.{ED7BA470-8E54-465E-825C-99712043E01C}，当然这里的“GodMode”不是必须的，可以选择任何喜欢的名字，起作用的是小数点后面的GUID。 回车之后，“上帝”就现身了。 进入此文件夹，一坨坨系统设置就在那里恭候大驾了。 在 Windows Server 2008 中也是一样的哦！ Read other posts: 隐藏磁盘分区Q U盘检测软件：ChipGenius，MyDiskTest 《塞尔达传说：黎明公主》攻略：角色介绍 2011.5.15我们的婚礼（二）——迎亲篇 2011.5.15我们的婚礼（三）——准备篇]]></description>
			<content:encoded><![CDATA[<div style="float:left;"><img width="85" height="78" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/godmode2.png" class="attachment-post-thumbnail wp-post-image" alt="Win7 God Mode Overview" title="godmode2" /></div><p>在 Windows 7 里，“上帝”能做什么？</p>
<p>一个简单的方法就可以调出调整 Windows 7 系统里全部功能的面板，这个小小的技巧可以让你控制你电脑中的一切。<span id="more-784"></span></p>
<p>启动“上帝模式”的方法非常简单，随便找个地方建立一个文件夹，将其命名为<div class="codecolorer-container text geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">GodMode.{ED7BA470-8E54-465E-825C-99712043E01C}</div></div>，当然这里的“GodMode”不是必须的，可以选择任何喜欢的名字，起作用的是小数点后面的GUID。</p>
<div id="attachment_790" class="wp-caption alignnone" style="width: 301px"><img alt="创建GodMode文件夹" class="size-full wp-image-790" height="239" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/godmode1.png" title="godmode1" width="291" /><p class="wp-caption-text">创建GodMode文件夹</p></div>
<p>回车之后，“上帝”就现身了。</p>
<p><img alt="Win7 God Mode Overview" class="alignnone size-full wp-image-785" height="78" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/godmode2.png" title="godmode2" width="85" /></p>
<p>进入此文件夹，一坨坨系统设置就在那里恭候大驾了。</p>
<div id="attachment_791" class="wp-caption alignnone" style="width: 688px"><img alt="Windows 7 上帝模式" class="size-full wp-image-791" height="585" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/godmode3.png" title="godmode3" width="678" /><p class="wp-caption-text">Windows 7 上帝模式</p></div>
<p>在 Windows Server 2008 中也是一样的哦！</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/hide-drive-q.html' rel='bookmark' title='隐藏磁盘分区Q'>隐藏磁盘分区Q</a></li>
<li><a href='http://www.gocalf.com/blog/check-udisk.html' rel='bookmark' title='U盘检测软件：ChipGenius，MyDiskTest'>U盘检测软件：ChipGenius，MyDiskTest</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-characters.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：角色介绍'>《塞尔达传说：黎明公主》攻略：角色介绍</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-2.html' rel='bookmark' title='2011.5.15我们的婚礼（二）——迎亲篇'>2011.5.15我们的婚礼（二）——迎亲篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-3.html' rel='bookmark' title='2011.5.15我们的婚礼（三）——准备篇'>2011.5.15我们的婚礼（三）——准备篇</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/win7-god-mode.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>数学趣题WWWDOT-GOOGLE=DOTCOM</title>
		<link>http://www.gocalf.com/blog/puzzle-wwwdot-google-dotcom.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=puzzle-wwwdot-google-dotcom</link>
		<comments>http://www.gocalf.com/blog/puzzle-wwwdot-google-dotcom.html#comments</comments>
		<pubDate>Wed, 13 Jul 2011 14:49:47 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[数学]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Math]]></category>
		<category><![CDATA[Puzzle]]></category>
		<category><![CDATA[智力题]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=754</guid>
		<description><![CDATA[以前见到一道关于Google的数字游戏题目，要求解开隐秘的等式WWWDOT - GOOGLE = DOTCOM，每个字母代表十个阿拉伯数字中的一个且各不相同，每个六位数字最高位都不是0，当然显而易见地，E和M是可以互换的。对于一个程序员，解决这个问题是很容易的，但今天我要讲讲小学生是怎么解决这个问题的。 把目标等式写成小学生习惯的竖式： \begin{matrix} &#038; W &#038; W &#038; W &#038; D &#038; O &#038; T\\ - &#038; G &#038; O &#038; O &#038; G &#038; L &#038; E\\ \hline &#038; D &#038; O &#038; T &#038; C &#038; O &#038; M\end{matrix} 先罗嗦一下，对于竖式中的任何一列，X - Y = Z，只有四种情况： 没有被低位借位，也不向高位借位，也就是真正的X - Y = Z； [...]]]></description>
			<content:encoded><![CDATA[<p>以前见到一道关于Google的数字游戏题目，要求解开隐秘的等式<code class="codecolorer text geshi"><span class="text">WWWDOT - GOOGLE = DOTCOM</span></code>，每个字母代表十个阿拉伯数字中的一个且各不相同，每个六位数字最高位都不是0，当然显而易见地，E和M是可以互换的。对于一个程序员，解决这个问题是很容易的，但今天我要讲讲小学生是怎么解决这个问题的。<span id="more-754"></span></p>
<p>把目标等式写成小学生习惯的竖式：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_c069641437ed1161a2dba486a0705819.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{matrix} & W & W & W & D & O & T\\ - & G & O & O & G & L & E\\ \hline & D & O & T & C & O & M\end{matrix}" title="\begin{matrix} & W & W & W & D & O & T\\ - & G & O & O & G & L & E\\ \hline & D & O & T & C & O & M\end{matrix}" /></span><script type='math/tex'>\begin{matrix} & W & W & W & D & O & T\\ - & G & O & O & G & L & E\\ \hline & D & O & T & C & O & M\end{matrix}</script></p>
<p>先罗嗦一下，对于竖式中的任何一列，<code class="codecolorer text geshi"><span class="text">X - Y = Z</span></code>，只有四种情况：</p>
<ol>
<li>没有被低位借位，也不向高位借位，也就是真正的<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_bce3df88ee3f9e1c207cc07fa5c2eb96.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="X - Y = Z" title="X - Y = Z" /></span><script type='math/tex'>X - Y = Z</script>；</li>
<li>没有被低位借位，但向高位借了一位，即<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_eb0c2eb4b90fbe51ae48a65c6bdea15e.gif' style='vertical-align: middle; border: none; ' class='tex' alt="(10+X) - Y = Z" title="(10+X) - Y = Z" /></span><script type='math/tex'>(10+X) - Y = Z</script>，或记做<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_4f890852bfcf08b0c706964156675a10.gif' style='vertical-align: middle; border: none; ' class='tex' alt="X_{+} - Y = Z" title="X_{+} - Y = Z" /></span><script type='math/tex'>X_{+} - Y = Z</script>；</li>
<li>被低位借位，但不向高位借位，即<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_75e8ae7c8e9e4717fe81b5cb0e12d77f.gif' style='vertical-align: middle; border: none; ' class='tex' alt="(X-1) - Y = Z" title="(X-1) - Y = Z" /></span><script type='math/tex'>(X-1) - Y = Z</script>，或记做<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_f6f3445a2b3ef931c2554ce23a3f9f8c.gif' style='vertical-align: middle; border: none; ' class='tex' alt="X^{-} - Y = Z" title="X^{-} - Y = Z" /></span><script type='math/tex'>X^{-} - Y = Z</script>；</li>
<li>被低位借位，也向高位借位，即<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_5afe2dd6ac62f1f3ba344386642ecb90.gif' style='vertical-align: middle; border: none; ' class='tex' alt="(10+X-1) - Y = Z" title="(10+X-1) - Y = Z" /></span><script type='math/tex'>(10+X-1) - Y = Z</script>，或记做<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_22562d9829cf3e20b73b0f8f40e26510.gif' style='vertical-align: middle; border: none; ' class='tex' alt="X^{-}_{+} - Y = Z" title="X^{-}_{+} - Y = Z" /></span><script type='math/tex'>X^{-}_{+} - Y = Z</script>。</li>
</ol>
<p>接下来就找竖式中的特殊情况。先看十位<code class="codecolorer text geshi"><span class="text">O - L = O</span></code>，在上述四种情况中，只有两种是可能的，即<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_e60b38e37871161add52eb0c7e35da7a.gif' style='vertical-align: middle; border: none; ' class='tex' alt="O_{+}^{-} - L = O \Rightarrow L=9" title="O_{+}^{-} - L = O \Rightarrow L=9" /></span><script type='math/tex'>O_{+}^{-} - L = O \Rightarrow L=9</script>和<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_ae1da57199346dbd3cfb335d05c8b421.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="O - L = O \Rightarrow L=0" title="O - L = O \Rightarrow L=0" /></span><script type='math/tex'>O - L = O \Rightarrow L=0</script>。</p>
<p>然后看千位和万位，被减数都是W，减数都是O，但结果却不同，说明在这两位的借位情况肯定不一样，也就只有两种可能，再结合前面提到的十位上的两种情况，可以得到：</p>
<ol>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_b10ed61481b06dd76071640c75719281.gif' style='vertical-align: middle; border: none; ' class='tex' alt="W_{+}-O=T" title="W_{+}-O=T" /></span><script type='math/tex'>W_{+}-O=T</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_bbb7e9cee0f268c1b5ed79332494d1a3.gif' style='vertical-align: middle; border: none; ' class='tex' alt="W^{-}_{+}-O=O" title="W^{-}_{+}-O=O" /></span><script type='math/tex'>W^{-}_{+}-O=O</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_5121c3ae5b52d0006cfc2b22d9a244d4.gif' style='vertical-align: middle; border: none; ' class='tex' alt="W^{-}-G=D" title="W^{-}-G=D" /></span><script type='math/tex'>W^{-}-G=D</script>
<ol>
<li><code class="codecolorer text geshi"><span class="text">L = 0</span></code>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_27779338399e879be23111165519e2bd.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="T - E = M" title="T - E = M" /></span><script type='math/tex'>T - E = M</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_baaf27b3a7a4be37c13cd41b323d8497.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="D - G = C" title="D - G = C" /></span><script type='math/tex'>D - G = C</script>；</li>
<li><code class="codecolorer text geshi"><span class="text">L = 9</span></code>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_a68a7363245de99bf28e9ed0f151aaa2.gif' style='vertical-align: middle; border: none; ' class='tex' alt="T_{+} - E = M" title="T_{+} - E = M" /></span><script type='math/tex'>T_{+} - E = M</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_f0c4d1df119517411012254560ea36c3.gif' style='vertical-align: middle; border: none; ' class='tex' alt="D^{-} - G = C" title="D^{-} - G = C" /></span><script type='math/tex'>D^{-} - G = C</script>；</li>
</ol>
</li>
<li><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_d7ef98649cbc07ac44b0fb676b05243b.gif' style='vertical-align: middle; border: none; ' class='tex' alt="W^{-}-O=T" title="W^{-}-O=T" /></span><script type='math/tex'>W^{-}-O=T</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_661162b9345c55390c75e843bfc577dd.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="W-O=O" title="W-O=O" /></span><script type='math/tex'>W-O=O</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_28c0eca8f5e5ccb728e104e9a043da41.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="W-G=D" title="W-G=D" /></span><script type='math/tex'>W-G=D</script>
<ol>
<li><code class="codecolorer text geshi"><span class="text">L = 0</span></code>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_27779338399e879be23111165519e2bd.gif' style='vertical-align: middle; border: none; padding-bottom:1px;' class='tex' alt="T - E = M" title="T - E = M" /></span><script type='math/tex'>T - E = M</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_d22486a254b297690a9ab262e0322d05.gif' style='vertical-align: middle; border: none; ' class='tex' alt="D_{+} - G = C" title="D_{+} - G = C" /></span><script type='math/tex'>D_{+} - G = C</script>；</li>
<li><code class="codecolorer text geshi"><span class="text">L = 9</span></code>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_a68a7363245de99bf28e9ed0f151aaa2.gif' style='vertical-align: middle; border: none; ' class='tex' alt="T_{+} - E = M" title="T_{+} - E = M" /></span><script type='math/tex'>T_{+} - E = M</script>，<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_89fbdd32cb17d98eafe87b59894ba84a.gif' style='vertical-align: middle; border: none; ' class='tex' alt="D^{-}_{+} - G = C" title="D^{-}_{+} - G = C" /></span><script type='math/tex'>D^{-}_{+} - G = C</script>。</li>
</ol>
</li>
</ol>
<p>先看情况1，可以推出：<code class="codecolorer text geshi"><span class="text">T = O + 1， W = 2 * O - 9，G + D = W - 1，G &lt; D</span></code>（因为百位上的减法没有向千位借位）。再根据W、O、D都不能为零，因此有<code class="codecolorer text geshi"><span class="text">1 &lt;= G &lt; D &lt;= W - 2 &lt;= 7</span></code>，<code class="codecolorer text geshi"><span class="text">4 &lt;= G + D + 1 = W = 2 * O - 9 &lt;= 8</span></code>，于是<code class="codecolorer text geshi"><span class="text">7 &lt;= O &lt;= 8</span></code>，这样的话：</p>
<ul>
<li>如果<code class="codecolorer text geshi"><span class="text">O = 7</span></code>，那么<code class="codecolorer text geshi"><span class="text">G + D = 2 * O - 10 = 4</span></code>，得到<code class="codecolorer text geshi"><span class="text">G = 1，D = 3</span></code>。那如果<code class="codecolorer text geshi"><span class="text">L = 9</span></code>，就有<code class="codecolorer text geshi"><span class="text">C = (D - 1) - G = 1 = G</span></code>，不符合题目。如果<code class="codecolorer text geshi"><span class="text">L = 0</span></code>，则<code class="codecolorer text geshi"><span class="text">C = 2</span></code>，<code class="codecolorer text geshi"><span class="text">E + M = T = O + 1 = 8 = (1 + 7) or (2 + 6) or (3 + 5)</span></code>，无法给E、M找到不重复的数字。</li>
<li>因此只能是<code class="codecolorer text geshi"><span class="text">O = 8，T = 9，L = 0</span></code>，又有<code class="codecolorer text geshi"><span class="text">G + D = 5，D - G = C</span></code>，可以得到G、D、C分别是1、5、4。于是<code class="codecolorer text geshi"><span class="text">E + M = T = 9</span></code>，得到E、M分别为3、6或者6、3。得到此题的一组解。</li>
</ul>
<p>用同样的方法分析情况2，可以得到<code class="codecolorer text geshi"><span class="text">W = 2 * O，T = O - 1，G + D = W，G &gt; D</span></code>&nbsp;，因此有<code class="codecolorer text geshi"><span class="text">1 &lt;= D &lt; G &lt;= W - 1 &lt;= 8</span></code>，<code class="codecolorer text geshi"><span class="text">3 &lt;= D + E &lt;= W = 2 * O &lt;= 9</span></code>，得到<code class="codecolorer text geshi"><span class="text">2 &lt;= O &lt;= 4</span></code>。但是根据C与D和G的关系不难发现，不论O、L取什么值，都无法找到不重复的C值。因此第二种情况无解。</p>
<p>综上，可以得到此问题唯一的一对解：<code class="codecolorer text geshi"><span class="text">O = 8，T = 9，W = 7，G = 1，D = 5，L = 0，C = 4，{E, M} = {3, 6}</span></code>，代入原方程得到：</p>
<p><span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_10aa577abc2890fe0b8aa68cd586b799.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{matrix} & 7 & 7 & 7 & 5 & 8 & 9\\ - & 1 & 8 & 8 & 1 & 0 & 3\\ \hline & 5 & 8 & 9 & 4 & 8 & 6\end{matrix}" title="\begin{matrix} & 7 & 7 & 7 & 5 & 8 & 9\\ - & 1 & 8 & 8 & 1 & 0 & 3\\ \hline & 5 & 8 & 9 & 4 & 8 & 6\end{matrix}" /></span><script type='math/tex'>\begin{matrix} & 7 & 7 & 7 & 5 & 8 & 9\\ - & 1 & 8 & 8 & 1 & 0 & 3\\ \hline & 5 & 8 & 9 & 4 & 8 & 6\end{matrix}</script> 或者是&nbsp;<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_daa31524a1eaccb2bb163f4ab3e4dc1f.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\begin{matrix} & 7 & 7 & 7 & 5 & 8 & 9\\ - & 1 & 8 & 8 & 1 & 0 & 6\\ \hline & 5 & 8 & 9 & 4 & 8 & 3\end{matrix}" title="\begin{matrix} & 7 & 7 & 7 & 5 & 8 & 9\\ - & 1 & 8 & 8 & 1 & 0 & 6\\ \hline & 5 & 8 & 9 & 4 & 8 & 3\end{matrix}" /></span><script type='math/tex'>\begin{matrix} & 7 & 7 & 7 & 5 & 8 & 9\\ - & 1 & 8 & 8 & 1 & 0 & 6\\ \hline & 5 & 8 & 9 & 4 & 8 & 3\end{matrix}</script></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/puzzle-wwwdot-google-dotcom.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于LaTeX插件再啰嗦几句</title>
		<link>http://www.gocalf.com/blog/latex-plugin-more.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=latex-plugin-more</link>
		<comments>http://www.gocalf.com/blog/latex-plugin-more.html#comments</comments>
		<pubDate>Mon, 11 Jul 2011 15:43:37 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[建站]]></category>
		<category><![CDATA[LaTeX]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[WordPress Plugin]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=683</guid>
		<description><![CDATA[对LaTeX for WordPress插件做了一点小小的改动，修复了在启用MathJax时无法显示公式源码的问题。还将公式的shortcode限定为latex。]]></description>
			<content:encoded><![CDATA[<p>在<a href="http://www.gocalf.com/blog/latex-wordpress.html" target="_blank" title="WordPress数学公式插件LaTeX">WordPress数学公式插件LaTeX</a>中推荐了Zhiqiang同学的WordPress插件LaTeX for WordPress，这个插件可以方便地以MathJax或者图片方式展示文章中的<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_c51d7e23458ca0e7373a8ed6ab56b2b9.gif' style='vertical-align: middle; border: none; ' class='tex' alt="\LaTeX" title="\LaTeX" /></span><script type='math/tex'>\LaTeX</script>公式，效果美观，使用方便。</p>
<p>不过由于使用习惯不同，我在使用这个插件的过程中也遇到了一些问题，于是对这个插件做了一点小小的修改，记录在此。</p>
<p>这次修改主要要解决两个问题：</p>
<ol>
<li>在启用MathJax的情况下，修复$$...!$$无法显示公式源码的问题。</li>
<li>限制公式的修饰符为[<!-- -->latex]和[/latex]</li>
</ol>
<p><span id="more-683"></span></p>
<p>根据<a href="http://wordpress.org/extend/plugins/latex/" target="_blank" title="LaTeX for WordPress">LaTeX for WordPress</a>主页上的说明，如果不想对公式进行渲染，只显示公式的源码，需要在第二个$$前面加!。但在实际使用中发现开启了MathJax的时候无法实现这一效果。仔细看了一下MathJax的文档，原来虽然插件把<code class="codecolorer text geshi"><span class="text">$$a^2+b^2+c^2!$$</span></code>这样的代码转换成了<code class="codecolorer text geshi"><span class="text">\(a^2+b^2+c^2!\)</span></code>，但后者又被MathJax的JavaScript给渲染成<span class='MathJax_Preview'><img src='http://www.gocalf.com/blog/wp-content/plugins/latex/cache/tex_3f3c3043613e89140e76c4b543d4fa88.gif' style='vertical-align: middle; border: none; ' class='tex' alt="a^2+b^2+c^2" title="a^2+b^2+c^2" /></span><script type='math/tex'>a^2+b^2+c^2</script>了。而要解决这个问题也很简单，只要给页面的body标签添加一个tex2jax_ignore的class，就可以阻止MathJax的处理（参见<a href="http://www.mathjax.org/docs/1.1/options/tex2jax.html" target="_blank" title="The tex2jax Preprocessor">The tex2jax Preprocessor</a>）。</p>
<p>以我现在使用的LightWord主题为例，修改/wp-content/themes/lightword/header.php，把<div class="codecolorer-container php geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;body <span style="color: #000000; font-weight: bold;">&lt;?php</span> body_class<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&gt;</div></div>改成<div class="codecolorer-container php geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&lt;body <span style="color: #000000; font-weight: bold;">&lt;?php</span> body_class<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'tex2jax_ignore'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&gt;</div></div>即可。</p>
<p>至于公式的修饰符，插件支持\(...\)、\[...\]、$$...$$、[<!-- -->latex]...[/latex]、[tex]...[/tex]。虽然Zhiqiang推荐使用LaTeX的自有标记\( ...\)，但我还是担心这样的代码在一些程序源代码中也很容易出现（比如正则表达式），所以还是决定只用latex作为标记。这个修改很简单，只要对/wp-content/plugins/latex/latex.php（v3.1）做如下改动即可：</p>
<pre><div class="codecolorer-container diff geshi" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="diff codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #440088;">108c108,109</span><br />
<span style="color: #991111;">&lt; $regex = '#\$\$<span style="">&#40;</span>.*?<span style="">&#41;</span>\$\$#si';</span><br />
<span style="color: #888822;">---<br />
<span style="color: #00b000;">&gt; //$regex = '#\$\$<span style="">&#40;</span>.*?<span style="">&#41;</span>\$\$#si';</span></span><br />
<span style="color: #00b000;">&gt; $regex = '#\<span style="">&#91;</span>latex\<span style="">&#93;</span><span style="">&#40;</span>.*?<span style="">&#41;</span>\<span style="">&#91;</span>/latex\<span style="">&#93;</span>#si';</span><br />
<span style="color: #440088;">110c111</span><br />
<span style="color: #991111;">&lt; $toParse = str_replace<span style="">&#40;</span>array<span style="">&#40;</span>&quot;\<span style="">&#40;</span>&quot;, &quot;\<span style="">&#41;</span>&quot;, &quot;\<span style="">&#91;</span>&quot;, &quot;\<span style="">&#93;</span>&quot;, &quot;<span style="">&#91;</span>latex<span style="">&#93;</span>&quot;, &quot;<span style="">&#91;</span>tex<span style="">&#93;</span>&quot;, &quot;<span style="">&#91;</span>/latex<span style="">&#93;</span>&quot;, &quot;<span style="">&#91;</span>/tex<span style="">&#93;</span>&quot;<span style="">&#41;</span>, array<span style="">&#40;</span>&quot;$$&quot;, &quot; $$&quot;, &quot;$$!&quot;, &quot; $$&quot;, &quot;$$&quot;, &quot; $$&quot;, &quot;$$&quot;, &quot; $$&quot;<span style="">&#41;</span>, $toParse<span style="">&#41;</span>;</span><br />
<span style="color: #888822;">---<br />
<span style="color: #00b000;">&gt; //$toParse = str_replace<span style="">&#40;</span>array<span style="">&#40;</span>&quot;\<span style="">&#40;</span>&quot;, &quot;\<span style="">&#41;</span>&quot;, &quot;\<span style="">&#91;</span>&quot;, &quot;\<span style="">&#93;</span>&quot;, &quot;<span style="">&#91;</span>latex<span style="">&#93;</span>&quot;, &quot;<span style="">&#91;</span>/latex<span style="">&#93;</span>&quot;, &quot;<span style="">&#91;</span>tex<span style="">&#93;</span>&quot;, &quot;<span style="">&#91;</span>/tex<span style="">&#93;</span>&quot;<span style="">&#41;</span>, array<span style="">&#40;</span>&quot;$$&quot;, &quot; $$&quot;, &quot;$$!&quot;, &quot; $$&quot;, &quot;$$&quot;, &quot; $$&quot;, &quot;$$&quot;, &quot; $$&quot;<span style="">&#41;</span>, $toParse<span style="">&#41;</span>;</span></span></div></div></pre>
<p>这样修改之后，依旧支持插件原本的inline、single line以及显示源码的处理。要在单独的一行中显示公式，就在[<!-- -->latex]后面加!；如果要显示公式源码，就在[/latex]前面加!。</p>
<p>当然也期待Zhiqiang进一步完善插件，给用户提供更方便的设置选项。</p>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/latex-wordpress.html' rel='bookmark' title='WordPress数学公式插件LaTeX'>WordPress数学公式插件LaTeX</a></li>
<li><a href='http://www.gocalf.com/blog/wordpress-latex-old.html' rel='bookmark' title='为你的WordPress站点添加LaTeX支持'>为你的WordPress站点添加LaTeX支持</a></li>
<li><a href='http://www.gocalf.com/blog/mathjax-numerous-files.html' rel='bookmark' title='关于安装MathJax后占用文件过多的问题'>关于安装MathJax后占用文件过多的问题</a></li>
<li><a href='http://www.gocalf.com/blog/puzzle-wwwdot-google-dotcom.html' rel='bookmark' title='数学趣题WWWDOT-GOOGLE=DOTCOM'>数学趣题WWWDOT-GOOGLE=DOTCOM</a></li>
<li><a href='http://www.gocalf.com/blog/calendar-of-week.html' rel='bookmark' title='星期万年历'>星期万年历</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/latex-plugin-more.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>2011.5.15我们的婚礼——婚礼录像片头</title>
		<link>http://www.gocalf.com/blog/wedding-video-2.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=wedding-video-2</link>
		<comments>http://www.gocalf.com/blog/wedding-video-2.html#comments</comments>
		<pubDate>Fri, 08 Jul 2011 16:29:03 +0000</pubDate>
		<dc:creator>Angel</dc:creator>
				<category><![CDATA[日记]]></category>
		<category><![CDATA[Video]]></category>
		<category><![CDATA[婚礼]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=575</guid>
		<description><![CDATA[婚礼的录像有一个多小时，忒长鸟~~，在此，仅截取开头四分钟的小片头展示一下吧，每个环节都有一滴滴。hoho~~]]></description>
			<content:encoded><![CDATA[<p>婚礼的录像有一个多小时，忒长鸟~~，在此，仅截取开头四分钟的小片头展示一下吧，每个环节都有一滴滴。hoho~~</p>
	<video id="wp_mep_1" controls="controls" width="480" height="272" poster="http://www.gocalf.com/blog/wp-content/uploads/2011/07/wedding_video.jpg" preload="none" class="mejs-player " data-mejsoptions='{"features":["playpause","current","progress","duration","volume","tracks","fullscreen"]}'>
		<source src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/wedding_video.mp4" type="video/mp4" />
		<object width="480" height="272" type="application/x-shockwave-flash" data="http://www.gocalf.com/blog/wp-content/plugins/media-element-html5-video-and-audio-player/mediaelement/flashmediaelement.swf">
			<param name="movie" value="http://www.gocalf.com/blog/wp-content/plugins/media-element-html5-video-and-audio-player/mediaelement/flashmediaelement.swf" />
			<param name="flashvars" value="controls=true&amp;file=http://www.gocalf.com/blog/wp-content/uploads/2011/07/wedding_video.mp4" />			
		</object>		
	</video>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/wedding-video-1.html' rel='bookmark' title='2011.5.15我们的婚礼——开场视频'>2011.5.15我们的婚礼——开场视频</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-2.html' rel='bookmark' title='2011.5.15我们的婚礼（二）——迎亲篇'>2011.5.15我们的婚礼（二）——迎亲篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-3.html' rel='bookmark' title='2011.5.15我们的婚礼（三）——准备篇'>2011.5.15我们的婚礼（三）——准备篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-1.html' rel='bookmark' title='2011.5.15我们的婚礼（一）——出发篇'>2011.5.15我们的婚礼（一）——出发篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-4.html' rel='bookmark' title='2011.5.15我们的婚礼（四）——仪式篇'>2011.5.15我们的婚礼（四）——仪式篇</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/wedding-video-2.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
<enclosure url="http://www.gocalf.com/blog/wp-content/uploads/2011/07/wedding_video.mp4" length="30728883" type="video/mp4" />
	
		<series:name><![CDATA[2011.5.15我们的婚礼]]></series:name>
	</item>
		<item>
		<title>2011.5.15我们的婚礼——开场视频</title>
		<link>http://www.gocalf.com/blog/wedding-video-1.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=wedding-video-1</link>
		<comments>http://www.gocalf.com/blog/wedding-video-1.html#comments</comments>
		<pubDate>Fri, 08 Jul 2011 15:54:45 +0000</pubDate>
		<dc:creator>Angel</dc:creator>
				<category><![CDATA[日记]]></category>
		<category><![CDATA[Video]]></category>
		<category><![CDATA[婚礼]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=569</guid>
		<description><![CDATA[为了这个婚礼的开场视频，两个人翻箱倒柜地忆童年折腾了好久。用心做的成长相册，分享一下吧~ ：）]]></description>
			<content:encoded><![CDATA[<p>为了这个婚礼的开场视频，两个人翻箱倒柜地忆童年折腾了好久。用心做的成长相册，分享一下吧~ ：）</p>
	<video id="wp_mep_2" controls="controls" width="480" height="320" poster="http://www.gocalf.com/blog/wp-content/uploads/2011/07/growth_photo_album.jpg" preload="none" class="mejs-player " data-mejsoptions='{"features":["playpause","current","progress","duration","volume","tracks","fullscreen"]}'>
		<source src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/growth_photo_album.mp4" type="video/mp4" />
		<object width="480" height="320" type="application/x-shockwave-flash" data="http://www.gocalf.com/blog/wp-content/plugins/media-element-html5-video-and-audio-player/mediaelement/flashmediaelement.swf">
			<param name="movie" value="http://www.gocalf.com/blog/wp-content/plugins/media-element-html5-video-and-audio-player/mediaelement/flashmediaelement.swf" />
			<param name="flashvars" value="controls=true&amp;file=http://www.gocalf.com/blog/wp-content/uploads/2011/07/growth_photo_album.mp4" />			
		</object>		
	</video>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/wedding-video-2.html' rel='bookmark' title='2011.5.15我们的婚礼——婚礼录像片头'>2011.5.15我们的婚礼——婚礼录像片头</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-2.html' rel='bookmark' title='2011.5.15我们的婚礼（二）——迎亲篇'>2011.5.15我们的婚礼（二）——迎亲篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-3.html' rel='bookmark' title='2011.5.15我们的婚礼（三）——准备篇'>2011.5.15我们的婚礼（三）——准备篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-1.html' rel='bookmark' title='2011.5.15我们的婚礼（一）——出发篇'>2011.5.15我们的婚礼（一）——出发篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-4.html' rel='bookmark' title='2011.5.15我们的婚礼（四）——仪式篇'>2011.5.15我们的婚礼（四）——仪式篇</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/wedding-video-1.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://www.gocalf.com/blog/wp-content/uploads/2011/07/growth_photo_album.mp4" length="33059637" type="video/mp4" />
	
		<series:name><![CDATA[2011.5.15我们的婚礼]]></series:name>
	</item>
		<item>
		<title>iPad 2 iOS 4.3.3 可以越狱了</title>
		<link>http://www.gocalf.com/blog/ipad2-433-jailbreak.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ipad2-433-jailbreak</link>
		<comments>http://www.gocalf.com/blog/ipad2-433-jailbreak.html#comments</comments>
		<pubDate>Thu, 07 Jul 2011 06:32:48 +0000</pubDate>
		<dc:creator>Calf</dc:creator>
				<category><![CDATA[数码电子]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[JailBreak]]></category>
		<category><![CDATA[越狱]]></category>

		<guid isPermaLink="false">http://www.gocalf.com/blog/?p=544</guid>
		<description><![CDATA[iOS 4.3.3可以越狱了。]]></description>
			<content:encoded><![CDATA[<p>原以为iPad 2的越狱会遥遥无期，没想到突然就传出已经可以越狱的消息，大神Comex又一次找到了PDF漏洞，跟去年的iPhone4越狱一样，无需连接电脑只要有WiFi就可以。</p>
<p>不过现在还只有iOS 4.3.3可以越狱，低版本没有这个漏洞。低版本的就备份一下shsh之后赶紧升级吧。<br />
<span id="more-544"></span></p>
<p>步骤非常简单：</p>
<ol>
<li>确认当前固件版本是iOS 4.3.3 (8J2)（Settings-&gt;General-&gt;About-&gt;Version）。</li>
<li>开启浏览器Safari。</li>
<li>在地址栏中敲入<a href="http://www.jailbreakme.com" target="_blank" title="www.jailbreakme.com">http://www.jailbreakme.com</a>（上次iPhone 4也是这样的），打开页面。</li>
<li>在左侧Cydia图标下方可以看到有个FREE按钮（据说以后iOS越狱将要收费，似乎看到前兆了），点击。</li>
<li>FREE按钮变成INSTALL，再点击。</li>
<li>Safari被自动关闭，在桌面上可以看到出现了Cydia的图标，并且正在下载中。</li>
<li>等待下载完成，打开Cydia，越狱成功。
<div id="attachment_547" class="wp-caption alignnone" style="width: 235px"><a href="http://www.gocalf.com/blog/wp-content/uploads/2011/07/cydia-ipad2-ios433.jpg" target="_blank"><img alt="Cydia on iPad2 iOS 4.3.3" class="size-medium wp-image-547 " height="300" src="http://www.gocalf.com/blog/wp-content/uploads/2011/07/cydia-ipad2-ios433-225x300.jpg" title="cydia-ipad2-ios433" width="225" /></a><p class="wp-caption-text">Cydia on iPad2 iOS 4.3.3</p></div>
</li>
<li>如果想装盗版的软件，可以添加hackluo.us源，地址是<a href="http://cydia.hackluo.us" target="_blank" title="cydia.hackluo.us">http://cydia.hackluo.us</a>。</li>
<li>在这个源中找到AppSync for 4.0+，安装即可。<a href="http://bbs.weiphone.com" target="_blank" title="威锋网">weiphone网</a>上说安装威锋源<a href="http://apt.weiphone.com" target="_blank" title="威锋源">http://apt.weiphone.com</a>的AppSync-for-4.0+，不过很多人都反映这个在安装的时候会出现Size Mismatch。我还是推荐从hackluo.us源安装。</li>
<li>另外还可以安装Installous 4（也在hackluo.us源中），利用这个软件就可以方便地搜索、下载、安装和更新盗版的app了。</li>
<li>最后还是要罗嗦一句，提倡正版。大多数apps都不贵，如果觉得好就买一个吧。越狱是为了把iPad玩的更好，而不仅仅是为了装盗版软件。</li>
</ol>
Read other posts:<ol>
<li><a href='http://www.gocalf.com/blog/check-udisk.html' rel='bookmark' title='U盘检测软件：ChipGenius，MyDiskTest'>U盘检测软件：ChipGenius，MyDiskTest</a></li>
<li><a href='http://www.gocalf.com/blog/zelda-tp-characters.html' rel='bookmark' title='《塞尔达传说：黎明公主》攻略：角色介绍'>《塞尔达传说：黎明公主》攻略：角色介绍</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-2.html' rel='bookmark' title='2011.5.15我们的婚礼（二）——迎亲篇'>2011.5.15我们的婚礼（二）——迎亲篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-3.html' rel='bookmark' title='2011.5.15我们的婚礼（三）——准备篇'>2011.5.15我们的婚礼（三）——准备篇</a></li>
<li><a href='http://www.gocalf.com/blog/wedding-1.html' rel='bookmark' title='2011.5.15我们的婚礼（一）——出发篇'>2011.5.15我们的婚礼（一）——出发篇</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://www.gocalf.com/blog/ipad2-433-jailbreak.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

