<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_HCOONa</title><subtitle type="text"/><id>http://feed.cnblogs.com/blog/u/46734/rss</id><updated>2012-05-01T07:44:52Z</updated><author><name>HCOONa</name><uri>http://www.cnblogs.com/HCOONa/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/HCOONa/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/46734/rss"/><entry><id>http://www.cnblogs.com/HCOONa/archive/2012/05/01/game-of-fibonacci-nim.html</id><title type="text">Fibonacci Nim取子游戏</title><summary type="text">有一堆 n 个石子，两个人轮流取石子，最后一个取完石子的人获胜。要求：  第一次取石子时不能将所有石子取光。  每一次至少取一个石子。  每一次可以取的石子数不超过上一个人取的石子数的二倍。求先手必败态构成的集合。</summary><published>2012-05-01T07:44:00Z</published><updated>2012-05-01T07:44:00Z</updated><author><name>HCOONa</name><uri>http://www.cnblogs.com/HCOONa/</uri></author><link rel="alternate" href="http://www.cnblogs.com/HCOONa/archive/2012/05/01/game-of-fibonacci-nim.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/HCOONa/archive/2012/05/01/game-of-fibonacci-nim.html"/><content type="html">&lt;p&gt;除了&lt;a href="http://www.cnblogs.com/HCOONa/archive/2012/04/24/game-of-nim1.html"&gt;上一篇&lt;/a&gt;说过的Nim取子游戏以外，我还遇到过一道比较奇特的Nim取子游戏。这一问题的复杂程度远超过上一个问题的复杂程度。下面让我们来看看，对于这样的一类问题，我们该如何进行求解。（&lt;a href="http://files.cnblogs.com/HCOONa/Fibonacci_Nim.pdf"&gt;PDF版由此下载&lt;/a&gt;）&lt;/p&gt;&lt;p&gt;&lt;strong&gt;问题描述&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;有一堆 &lt;em&gt;n &lt;/em&gt;个石子，两个人轮流取石子，最后一个取完石子的人获胜。要求：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;第一次取石子时不能将所有石子取光。&lt;/li&gt;&lt;li&gt;每一次至少取一个石子。&lt;/li&gt;&lt;li&gt;每一次可以取的石子数不超过上一个人取的石子数的二倍。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;求先手必败态构成的集合。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;寻找思路&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我们首先从较小的 &lt;em&gt;n&lt;/em&gt; 开始尝试（为方便起见，我们记先手为A，后手为B，用状态 &lt;em&gt;i&lt;/em&gt; 表示有 &lt;em&gt;i&lt;/em&gt; 个石子）：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;当 &lt;em&gt;n&lt;/em&gt;=2 时：&lt;/strong&gt; A取 1 个石子，到达状态 1；B取走 1 个石子。B获胜。即，先手必败。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;当 &lt;em&gt;n&lt;/em&gt;=3 时：&lt;/strong&gt; 若一开始，A取 1 个石子，到达状态 2；B取走 2 个石子；B获胜。若一开始A取 2 个石子，则B取走 1 个石子；B获胜。即，先手必败。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;当 &lt;em&gt;n&lt;/em&gt;=4 时：&lt;/strong&gt; 若一开始，A取 1 个石子，则B至多只能取 2 个石子，等同于当 &lt;em&gt;n&lt;/em&gt;=3 时的A。因此，当 &lt;em&gt;n&lt;/em&gt;=4 时，先手必胜。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;当 &lt;em&gt;n&lt;/em&gt;=5 时：&lt;/strong&gt; 一开始，若A取 1 个石子，则B相当于 &lt;em&gt;n&lt;/em&gt;=4 时的A，B必胜；一开始，若A取 2 个石子，则B可以将剩下的 3 个石子取光，B必胜。因此，当 &lt;em&gt;n&lt;/em&gt;=5 时，先手必败。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;当 &lt;em&gt;n&lt;/em&gt;=6 时：&lt;/strong&gt; 一开始，若A取 1 个石子，则B相当于 &lt;em&gt;n&lt;/em&gt;=5 时的A，B必败；因此，当 &lt;em&gt;n&lt;/em&gt;=6 时，先手必胜。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;从上面的这些尝试中，我们可以总结出一个基本的规律：每次取石子时，若当前有 &lt;em&gt;n&lt;/em&gt; 个石子，则至多可以取&lt;img src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chl=%5clceil+n%2f3+%5crceil+-+1" alt="\lceil n/3 \rceil - 1" /&gt;个石子，否则对方能够将剩下的石子全部取走。至于其他的规律，似乎并不显著，需要更多的实例继续观察。&lt;/p&gt;&lt;p&gt;此外，在尝试的过程中，我们还能发现额外的两个情况。&lt;/p&gt;&lt;ol&gt;&lt;li&gt;原问题的子问题不仅与石子个数有关，还与上一个人取的石子个数有关。&lt;/li&gt;&lt;li&gt;如果先手必败态具有显著的规律性的话，一定是因为有若干个&amp;ldquo;必败点&amp;rdquo;，一旦到达这些&amp;ldquo;必败点&amp;rdquo;，无论上一个人取了多少石子，轮到我们的时候都是必败的。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;现在发现的信息还不足以纯粹的从数学上解决这一问题，我们不妨进行更多的尝试。鉴于这一问题实际上手工算起来挺麻烦，我们不妨先写个效率较低程序来算这个问题。&lt;/p&gt;&lt;h2 id="sec_rec"&gt;递归解&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;假设当前有 &lt;em&gt;n&lt;/em&gt; 个石子，上一个人取了 &lt;em&gt;m&lt;/em&gt; 个石子，则判断当前先走的人是输还是赢的函数可以递归地定义为下面这样：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/HCOONa/201205/201205011543557104.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="image" src="http://images.cnblogs.com/cnblogs_com/HCOONa/201205/201205011543566124.png" alt="image" width="804" height="163" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;按照这样的定义，我们很容易给出一个递归的程序，主要的程序片段如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;int f(int n, int m)&lt;br/&gt;{&lt;br/&gt;    if(2 * m &amp;gt;= n) {&lt;br/&gt;        return 1;&lt;br/&gt;    }&lt;br/&gt;    /* "(n + 2) / 3" in integer operation equals to&lt;br/&gt;     * "ceiling(n / 3) - 1" in float operation.&lt;br/&gt;     */&lt;br/&gt;    int i = 1, bound = min((n + 2) / 3, 2 * m);&lt;br/&gt;    for(; i &amp;lt;= bound; i++) {&lt;br/&gt;        if(f(n - i, i) == 0) {&lt;br/&gt;            return 1;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    return 0;&lt;br/&gt;}&lt;/div&gt;&lt;p&gt;但是这个程序效率太低了，我用其计算&lt;img src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chl=n+%5cleq+50" alt="n \leq 50" /&gt;的结果，就花了不少时间，计算结果如下（其中P表示先手必败，N表示先手必胜）：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;P&amp;nbsp; P&amp;nbsp; P&amp;nbsp; N&amp;nbsp; P&amp;nbsp; N&amp;nbsp; N&amp;nbsp; P&amp;nbsp; N&amp;nbsp; N &lt;br /&gt;1&amp;nbsp; 2&amp;nbsp; 3&amp;nbsp; 4&amp;nbsp; 5&amp;nbsp; 6&amp;nbsp; 7&amp;nbsp; 8&amp;nbsp; 9 10     &lt;br /&gt;N&amp;nbsp; N&amp;nbsp; P&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N     &lt;br /&gt;11 12 13 14 15 16 17 18 19 20     &lt;br /&gt;P&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N     &lt;br /&gt;21 22 23 24 25 26 27 28 29 30     &lt;br /&gt;N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; P&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N     &lt;br /&gt;31 32 33 34 35 36 37 38 39 40     &lt;br /&gt;N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N&amp;nbsp; N     &lt;br /&gt;41 42 43 44 45 46 47 48 49 50&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;似乎规律仍然不太显著，考虑改进我们的算法，以计算更多的情况。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;动态规划解   &lt;/strong&gt;&lt;/p&gt;&lt;p&gt;不难看出，按照&lt;a href="#sec_rec"&gt;递归解&lt;/a&gt;中给出的递归定义进行计算，是有着很大量的重复计算的。这恰恰满足了动态规划解的两个条件：最优子结构和重叠子问题。 &lt;/p&gt;&lt;p&gt;为了保持解形式上的优雅，不破坏递归结构，顺便也是偷个懒，这里给出一个使用备忘录（memoize）法&lt;sup&gt;&lt;a href="#ref_1"&gt;1&lt;/a&gt;&lt;/sup&gt;的动态规划解。事实上，备忘录法的时间效率和一般的动态规划方法是一致的，只是比较浪费空间。下面给出部分代码。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;int f(int n, int m)&lt;br/&gt;{&lt;br/&gt;    if(2 * m &amp;gt;= n) {&lt;br/&gt;        return 1;&lt;br/&gt;    }&lt;br/&gt;    if(cache[n][m] != NAN) {&lt;br/&gt;        return cache[n][m];&lt;br/&gt;    }&lt;br/&gt;    /* "(n + 2) / 3" in integer operation equals to&lt;br/&gt;     * "ceiling(n / 3) - 1" in float operation.&lt;br/&gt;     */&lt;br/&gt;    int i = 1, bound = min((n + 2) / 3, 2 * m);&lt;br/&gt;    for(; i &amp;lt;= bound; i++) {&lt;br/&gt;        if(f(n - i, i) == 0) {&lt;br/&gt;            return cache[n][m] = 1;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;    return cache[n][m] = 0;&lt;br/&gt;}&lt;/div&gt;&lt;p&gt;用其计算&lt;img src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chl=n+%5cleq+1000" alt="n \leq 1000" /&gt;的先手必败态，得到结果：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;&amp;nbsp; 1&amp;nbsp;&amp;nbsp; 2&amp;nbsp;&amp;nbsp; 3&amp;nbsp;&amp;nbsp; 5&amp;nbsp;&amp;nbsp; 8&amp;nbsp; 13&amp;nbsp; 21&amp;nbsp; 34&amp;nbsp; 55&amp;nbsp; 89 &lt;br /&gt;144 233 377 610 987 &lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;数学上的&amp;ldquo;紧致解&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;通过观察计算结果，可以发现，先手必败态恰构成了Fibonacci数列。为叙述方便起见，如果一个数在Fibonacci数列中，我们称其为一个Fibonacci数。不妨猜测，对于&lt;img src="http://chart.apis.google.com/chart?cht=tx&amp;amp;chl=%5cforall+n+%5cin+%5cmathbb%7bN%7d%2c+n+%5cgeq+2" alt="\forall n \in \mathbb{N}, n \geq 2" /&gt;，当且仅当 &lt;em&gt;n&lt;/em&gt; 为一个Fibonacci数，有先手必败。 &lt;/p&gt;&lt;p&gt;粗略的想一想，大概用数学归纳法可以证明这一结论。大概就是在Fibonacci数的石子数时，不能一次将石子数拿到剩余另一个Fibonacci数；而一个非Fibonacci数的石子数开始拿能一次将石子数拿到剩余一个Fibonacci数。下面我们按照这一思路证明之。&lt;/p&gt;&lt;p&gt;使用 &lt;em&gt;f &lt;/em&gt;(&lt;em&gt;k &lt;/em&gt;) 表示第 &lt;em&gt;k&lt;/em&gt; 个Fibonacci数，其中 &lt;em&gt;f &lt;/em&gt;(0)=&lt;em&gt;f &lt;/em&gt;(1)=1。将剩余石子数为 &lt;em&gt;n&lt;/em&gt; 记为状态 &lt;em&gt;n&lt;/em&gt;。若游戏处于状态 &lt;em&gt;n&lt;/em&gt;，此时先手有必胜策略，则称状态 &lt;em&gt;n&lt;/em&gt; 处于N状态；若此时后手有必胜策略，则称状态 &lt;em&gt;n&lt;/em&gt; 处于P状态。（注意：一个状态处于P状态，当且仅当其按照游戏规则所能够到达的状态均为N状态；一个状态处于N状态，说明其能够按照游戏规则到达一个P状态。）&lt;/p&gt;&lt;p&gt;具体的证明过程，请见&lt;a href="http://files.cnblogs.com/HCOONa/Fibonacci_Nim.pdf"&gt;PDF版本的本文&lt;/a&gt;。更进一步的数学原理，请见参考资料2。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;参考资料&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;机械工业出版社&lt;a href="http://www.amazon.cn/%E7%AE%97%E6%B3%95%E5%AF%BC%E8%AE%BA-%E7%A7%91%E6%9B%BC/dp/B0011BVTRK"&gt;《算法导论（原书第 2 版）》&lt;/a&gt;，第 15 章 动态规划，15.3 动态规划基础 做备忘录 P207。 &lt;/li&gt;&lt;li&gt;&lt;a href="http://yjq24.blogbus.com/logs/46150651.html"&gt;EP8: Fibonacci Nim（斐波那契取石子博弈）&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;img src="http://www.cnblogs.com/HCOONa/aggbug/2477923.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/HCOONa/archive/2012/05/01/game-of-fibonacci-nim.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/HCOONa/archive/2012/04/24/game-of-nim1.html</id><title type="text">一道面试题（Nim取子游戏）——如何将数学思维应用到编程中</title><summary type="text">有16颗石子，两个人轮流取子，每次只能取一颗、两颗或者四颗石子，最后取完石子的人为负。问，先取子的人还是后取子的人有必胜策略。我们该如何一步步解决这一问题呢？</summary><published>2012-04-24T09:12:00Z</published><updated>2012-04-24T09:12:00Z</updated><author><name>HCOONa</name><uri>http://www.cnblogs.com/HCOONa/</uri></author><link rel="alternate" href="http://www.cnblogs.com/HCOONa/archive/2012/04/24/game-of-nim1.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/HCOONa/archive/2012/04/24/game-of-nim1.html"/><content type="html">&lt;p&gt;今天偶然遇到一道Nim取子游戏的题，大意如下：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;有16颗石子，两个人轮流取子，每次只能取一颗、两颗或者四颗石子，最后取完石子的人为负。问，先取子的人还是后取子的人有必胜策略。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;题目非常简单，已经非常熟悉博弈论或者Nim取子游戏的大牛，请移步&lt;a href="#advancedTopics"&gt;进阶话题&lt;/a&gt;。&lt;/p&gt;&lt;h2 id="findMinds"&gt;寻找思路&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;拿到一个特殊化的题目，如果没有思路的话，可以考虑先将题目转换为一般化的形式，再将一般化形式的题目特殊化到简单实例寻找规律。以本题为例，先将题目转换为一般形式：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;有&lt;em&gt; n &lt;/em&gt;颗石子，两个人轮流取子，每次只能取一颗、两颗或者四颗石子，最后取完石子的人为负。问，先取子的人还是后取子的人有必胜策略。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;考虑简单的情况：&lt;/p&gt;&lt;p&gt;当 &lt;em&gt;n&lt;/em&gt; = 1 时，先取子的人必然取完全部的石子，因此，先取子的人必负，从而后取子的人必胜；即，当 &lt;em&gt;n&lt;/em&gt; = 1 时，后取子的人有必胜策略。&lt;/p&gt;&lt;p&gt;当 &lt;em&gt;n&lt;/em&gt; = 2 时，先取子的人可以只取一颗石子，从而后取子的人进入上述 &lt;em&gt;n&lt;/em&gt; = 1 时先取子的情况；因此，当 &lt;em&gt;n&lt;/em&gt; = 2 时，先取子的人有必胜策略。&lt;/p&gt;&lt;p&gt;当 &lt;em&gt;n&lt;/em&gt; = 3 时，先取子的人可以只取两颗石子，从而后取子的人进入上述 &lt;em&gt;n&lt;/em&gt; = 1 时先取子的情况；因此，当 &lt;em&gt;n&lt;/em&gt; = 3 时，先取子的人有必胜策略。&lt;/p&gt;&lt;p&gt;当 &lt;em&gt;n&lt;/em&gt; = 4 时，先取子的人若只取一颗石子，则后取子的人将进入上述 &lt;em&gt;n&lt;/em&gt; = 3 时先取子的情况，后取子的人必胜；若先取子的人只取两颗石子，则后取子的人将进入上述 &lt;em&gt;n&lt;/em&gt; = 2 时先取子的情况，后取子的人必胜；先取子的人若取四颗石子，则恰将所有石子取光，从而后取子的人必胜；综上所述，当 &lt;em&gt;n&lt;/em&gt; = 4 时，后取子的人有必胜策略。&lt;/p&gt;&lt;p&gt;当 &lt;em&gt;n&lt;/em&gt; = 5 时，先取子的人若只取一颗石子，则后取子的人将进入上述 &lt;em&gt;n&lt;/em&gt; = 4 时先取子的情况，从而必输；因此，当 &lt;em&gt;n&lt;/em&gt; = 5 时，先取子的人有必胜策略。&lt;/p&gt;&lt;p&gt;为了方便起见，我们引入两个博弈论中的概念：P状态和N状态。如果双方都按照最佳策略进行游戏，我们可以将游戏中的每个状态依据其是先手必胜还是后手必胜分类。一个先手胜状态被认为是一个N状态（因为下一个玩家即将获胜），一个后手胜状态被认为是一个P状态（因为前一个玩家即将获胜）。P状态和N状态归纳性地描述如下：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;一个点v是P状态当且仅当它的所有后继都为N状态&lt;/p&gt;&lt;p&gt;一个点v是N状态当且仅当它的一些后继是P状态&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;在此我们稍微详细的解释一下P状态和N状态定义的实际意义。注意以下事实：如果当前游戏处于P状态，则先走的人必输，后走的人必胜（按照P状态的定义）。因此，无论当前处于何种状态，只要按照游戏规则进行了一步后，能够进入P状态，则当前先走的人必胜。因此，N状态可以转移到P状态，而P状态必然转移到N状态。这也就是P状态和N状态归纳性描述的实际意义。&lt;/p&gt;&lt;p&gt;为了不被这些繁琐的概念弄晕，我们不妨回到原来这道题目上。下面，我们使用P状态和N状态来标记这个取子游戏的先手必胜或者必负的情况。（下面一行表示游戏开始时有几个石子，0 的上面对应的 * 号表示，对于初始有 0 个石子的情况，没有定义这时是谁赢）&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p align="center"&gt;&lt;span style="font-family: Consolas;"&gt;* P N N P N N P N N P&amp;nbsp; &amp;hellip;&amp;hellip;&lt;/span&gt;&lt;/p&gt;&lt;p align="center"&gt;&lt;span style="font-family: Consolas;"&gt;0 1 2 3 4 5 6 7 8 9 10 &amp;hellip;&amp;hellip;&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;可以发现规律：当 &lt;em&gt;n&lt;/em&gt; mod 3 = 1 时，后手有必胜策略；其余情况，先手有必胜策略。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;形式化的证明&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;虽然我们通过观察发现了规律，但是我们不能保证我们发现的规律会一直保持下去。对于特定的这道题而言，我们只需将上面的状态转移表一直写到 &lt;em&gt;n&lt;/em&gt; = 16 的情况即可解题。但是我们不妨把眼光放的长远一些，考虑一般形式的解。&lt;/p&gt;&lt;p&gt;实际上，上面&lt;a href="#findMinds"&gt;寻找思路&lt;/a&gt;的过程中，暗示了我们应该如何证明这一结论。下面我们采用数学归纳法证明这一结论：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;当 &lt;em&gt;n&lt;/em&gt; mod 3 = 1 时，游戏处于P状态；其余情况，游戏处于N状态。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;归纳基础：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;当 &lt;em&gt;n&lt;/em&gt; = 1 时，游戏处于P状态；当 &lt;em&gt;n&lt;/em&gt; = 2 时，游戏处于N状态；当 &lt;em&gt;n&lt;/em&gt; = 3 时，游戏处于N状态。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;归纳假设：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;若 &lt;em&gt;n&lt;/em&gt; mod 3 = 0，则：(&lt;em&gt;n&lt;/em&gt; &amp;ndash; 3)处于N状态，(&lt;em&gt;n&lt;/em&gt; &amp;ndash; 2)处于P状态，(&lt;em&gt;n&lt;/em&gt; &amp;ndash; 1)处于N状态，&lt;em&gt;n&lt;/em&gt; 处于N状态；&lt;/p&gt;&lt;p&gt;若 &lt;em&gt;n&lt;/em&gt; mod 3 = 1，则：(&lt;em&gt;n&lt;/em&gt; &amp;ndash; 3)处于P状态，(&lt;em&gt;n&lt;/em&gt; &amp;ndash; 2)处于N状态，(&lt;em&gt;n&lt;/em&gt; &amp;ndash; 1)处于N状态，&lt;em&gt;n&lt;/em&gt; 处于P状态；&lt;/p&gt;&lt;p&gt;若 &lt;em&gt;n&lt;/em&gt; mod 3 = 2，则：(&lt;em&gt;n&lt;/em&gt; &amp;ndash; 3)处于N状态，(&lt;em&gt;n&lt;/em&gt; &amp;ndash; 2)处于N状态，(&lt;em&gt;n&lt;/em&gt; &amp;ndash; 1)处于P状态，&lt;em&gt;n&lt;/em&gt; 处于N状态。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;归纳证明：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;若 &lt;em&gt;n&lt;/em&gt; mod 3 = 0，则由于从状态(&lt;em&gt;n&lt;/em&gt; + 1)仅可以转换到状态 &lt;em&gt;n&lt;/em&gt;、状态(&lt;em&gt;n&lt;/em&gt; - 1)、状态(&lt;em&gt;n&lt;/em&gt; - 3)，而这三个状态均为N状态，因此状态(&lt;em&gt;n&lt;/em&gt; + 1)为P状态；（&lt;em&gt;n&lt;/em&gt; + 1 mod 3 = 1）&lt;/p&gt;&lt;p&gt;若 &lt;em&gt;n&lt;/em&gt; mod 3 = 1，则由于从状态(&lt;em&gt;n&lt;/em&gt; + 1)可以转换到状态 &lt;em&gt;n&lt;/em&gt;，而状态 &lt;em&gt;n&lt;/em&gt; 为P状态，因此状态(&lt;em&gt;n&lt;/em&gt; + 1)为N状态；（&lt;em&gt;n&lt;/em&gt; + 1 mod 3 = 2）&lt;/p&gt;&lt;p&gt;若 &lt;em&gt;n&lt;/em&gt; mod 3 = 2，则由于从状态(&lt;em&gt;n&lt;/em&gt; + 1)可以转换到状态(&lt;em&gt;n&lt;/em&gt; - 1)，而状态(&lt;em&gt;n&lt;/em&gt; - 1)为P状态，因此状态(&lt;em&gt;n&lt;/em&gt; + 1)为N状态。（&lt;em&gt;n&lt;/em&gt; + 1 mod 3 = 0）&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;综上所述，当 &lt;em&gt;n&lt;/em&gt; mod 3 = 1 时，游戏处于P状态；其余情况，游戏处于N状态。&lt;/p&gt;&lt;p&gt;有了这一结论，对于给定的石子数目 &lt;em&gt;n&lt;/em&gt;，如果按照题目中所叙述的规则来进行游戏，我们只需要判定 &lt;em&gt;n&lt;/em&gt; mod 3 是否等于 1，即可给出先手还是后手有必胜策略的答案。因此，对应于这一题目，我们所编写的程序也相当简单了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;递归形式&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;对于题目中给定的这种简单情况，确实很容易发现其规律并证明其正确性。但是有的时候，解的规律是很不显然的，或者是难以证明的。对于这种情况，我们可以考虑，从工程上解决这一问题，而不是找到数学上的&amp;ldquo;紧形式&amp;rdquo;的解。放开这一限制，我们虽然抛弃了数学上的美感，但是却能够解决更广泛的一系列问题。这里不对此进行进一步的展开讨论，而是继续就本问题进行讨论。&lt;/p&gt;&lt;p&gt;在&lt;a href="#findMinds"&gt;寻找思路&lt;/a&gt;的过程中，给了我们足够的提示来解决这一问题。经过细致的归纳和整理，我们可以得到一个递归的解：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/HCOONa/201204/201204241711429610.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="Recursive-equation" src="http://images.cnblogs.com/cnblogs_com/HCOONa/201204/201204241711431693.png" alt="\begin{equation}&amp;amp;#13;&amp;amp;#10;f(n) = &amp;amp;#13;&amp;amp;#10;\begin{cases}&amp;amp;#13;&amp;amp;#10;false &amp;amp;amp; \text{if $n = 1$ or $n = 4$} \\&amp;amp;#13;&amp;amp;#10;true &amp;amp;amp; \text{if $n = 2$ or $n = 3$} \\&amp;amp;#13;&amp;amp;#10;true &amp;amp;amp; \text{if $f(n-1) =$ false or $f(n-2) =$ false or $f(n-4) =$ false} \\&amp;amp;#13;&amp;amp;#10;false &amp;amp;amp; \text{else}&amp;amp;#13;&amp;amp;#10;\end{cases}&amp;amp;#13;&amp;amp;#10;\end{equation}" width="640" height="136" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;从这个递归解出发，我们可以写出一个递归函数来处理这一问题：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;bool f(int n)&lt;br/&gt;{&lt;br/&gt;    if(n == 1 || n == 4) return false;&lt;br/&gt;    if(n == 2 || n == 3) return true;&lt;br/&gt;    if( !f(n - 1) || !f(n - 2) || !f(n - 4) ) return true;&lt;br/&gt;    return false;&lt;br/&gt;}&lt;/div&gt;&lt;p&gt;当然，这个解显然不是最优的。例如：在计算 &lt;em&gt;f &lt;/em&gt;(5) 的时候，我们需要计算 &lt;em&gt;f &lt;/em&gt;(4)；而在计算 &lt;em&gt;f &lt;/em&gt;(6) 的时候，我们仍然需要计算 &lt;em&gt;f &lt;/em&gt;(4)。这正是动态规划算法所具有的重叠子问题性质。而上面给出的递归解，则符合了动态规划算法的最优子结构性质。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;动态规划解&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;既然这一问题满足动态规划算法的所有性质，我们可以使用较高效的动态规划算法来解决这一问题。如何重新安排计算的顺序，从而高效、无重复的计算 &lt;em&gt;f &lt;/em&gt;(&lt;em&gt;n&lt;/em&gt;)，这是一个较为复杂的问题。但是对于现在我们所面对的这一特定问题，其答案却不难回答。我们只需要设定好初始条件，然后由小到大顺序的计算&lt;em&gt;f &lt;/em&gt;(&lt;em&gt;n&lt;/em&gt;)，即可无重复的得到所需要的结果。一个动态规划算法如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;bool f(int n)&lt;br/&gt;{&lt;br/&gt;    if(n &amp;lt;= 0) return false;&lt;br/&gt;    bool *states = (bool *)malloc(sizeof(bool) * n);&lt;br/&gt;    states[0] = states[3] = false;&lt;br/&gt;    states[1] = states[2] = true;&lt;br/&gt;    for(int i = 4; i &amp;lt; n; i++) {&lt;br/&gt;        states[i] = !(states[i - 1]&lt;br/&gt;                    &amp;amp;&amp;amp; states[i - 2]&lt;br/&gt;                    &amp;amp;&amp;amp; states[i - 4]);&lt;br/&gt;         /* According to De Morgan's laws */&lt;br/&gt;    }&lt;br/&gt;    return states[n - 1];&lt;br/&gt;}&lt;/div&gt;&lt;p&gt;这个算法是很容易想到的，但是考虑到我们在求递归解的时候，只需要之前的四个数据即可，我们还可以继续优化这个算法。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;bool fn(int n)&lt;br/&gt;{&lt;br/&gt;    if(n &amp;lt;= 0) return false; /* We can return anything, because it has no real meaning. */&lt;br/&gt;    if(n == 1 || n == 4) return false;&lt;br/&gt;    if(n == 2 || n == 3) return true;&lt;br/&gt;/* a ~ fn(i - 4)&lt;br/&gt; * b ~ fn(i - 3)&lt;br/&gt; * c ~ fn(i - 2)&lt;br/&gt; * d ~ fn(i - 1)&lt;br/&gt; * f ~ fn(i)&lt;br/&gt; */&lt;br/&gt;    bool a = d = false, b = c = true;&lt;br/&gt;    for(int i = 5; i &amp;lt;= n; i++) {&lt;br/&gt;        bool f = !(a &amp;amp;&amp;amp; c &amp;amp;&amp;amp; d);&lt;br/&gt;        a = b; b = c; c = d; d = f;&lt;br/&gt;    }&lt;br/&gt;    return d;&lt;br/&gt;}&lt;/div&gt;&lt;h2 id="advancedTopics"&gt;进阶话题&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;《编程之美》P67~87&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/hsqdboke/archive/2012/04/21/2461034.html"&gt;Sprague-Grundy Function-SG函数--博弈论(3)&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/33923/what-is-tail-recursion"&gt;尾递归（tail-recursive）&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/HCOONa/aggbug/2468384.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/HCOONa/archive/2012/04/24/game-of-nim1.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/HCOONa/archive/2012/01/25/summary-in-USTC-fist-stage.html</id><title type="text">中科大软件学院第一学期总结</title><summary type="text">考研究生调剂到了中科大软件学院，现在看来是一件让我觉得十分幸运的事情。中科大的学习气氛非常的浓，课程的内容也十分有新意，虽然有新意，但是又都是很基础的内容，让我收获很大，很多课程给我带来了很大的启发。...</summary><published>2012-01-25T06:33:00Z</published><updated>2012-01-25T06:33:00Z</updated><author><name>HCOONa</name><uri>http://www.cnblogs.com/HCOONa/</uri></author><link rel="alternate" href="http://www.cnblogs.com/HCOONa/archive/2012/01/25/summary-in-USTC-fist-stage.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/HCOONa/archive/2012/01/25/summary-in-USTC-fist-stage.html"/><content type="html">&lt;p&gt;考研究生调剂到了中科大软件学院，现在看来是一件让我觉得十分幸运的事情。中科大的学习气氛非常的浓，课程的内容也十分有新意，虽然有新意，但是又都是很基础的内容，让我收获很大，很多课程给我带来了很大的启发。直到过年时候，才腾出时间来写上一篇总结，记录我这一学期的生活和学习。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;初来&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我一直是一个地地道道的北方人，生在北京，长在北京，却跑到哈尔滨读了四年书。哈工大学习负担不轻，假期也很短，一直没有时间到处玩玩，再加上自己比较懒，大学期间也就去了趟长春。这次考到了中科大苏州研究院，心中对于南方的风土人情很是期待，内心中也不乏有些忐忑。&lt;/p&gt;&lt;p&gt;开学前，我直接跑到了南京玩了一周，玩的十分痛快，题外话暂且不提，然后从南京坐高铁到了苏州。中科大苏州研究院地处独墅湖高教园区，正巧高铁有工业园区一站，我就在工业园区站下了车。人生地不熟找不到合适的公交，直接拦下一辆出租车奔着学校这边就来了。苏州的出租车司机素质感觉比较高，礼让行人等做的都很不错，开车也很规矩。出租车司机还很健谈，就像北京的老师傅一样，听说我是来上学的，给我说了很多苏州的情况。我是提前一天前来报道的，物业态度很不好，不过好在顺利办理了入住手续，搬进了宿舍。宿舍两人寝，上床下桌，屋子不小，但是什么都没有，不过比较干净，我开学前几天都在置备东西。苏州的空气很好，略显湿润但却不潮湿，气温跟北京差不多，略高3℃左右，我很适应。住宿的地方离学校不近，走路30分钟左右，不过每天都有班车。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;乍到&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;中科大开的课程都很有意思，很多课程我遗憾的没有抢到，不过幸好没有全抢到我喜欢的课程，不然估计得累到爆。曾经我很不理解哈佛的学生为什么一学期只有8门课程还累得要死，知道我来到了号称&amp;ldquo;不要命的来科大&amp;rdquo;的中科大，才彻底理解了原因。中科大的课很有意思，难度也颇高，想要学好，就要付出150%的努力，而且基本上我学的所有的课都需要这种程度的努力。&lt;/p&gt;&lt;p&gt;下面说说我都上了些什么课，都有什么好玩的内容。&lt;/p&gt;&lt;p&gt;英语免修过关考试侥幸水过，让我能够选一些其他我感兴趣的课程。一开始我选的是实用算法设计一课，第一节课时，老师负责任的指出此课程针对于没有算法基础的同学，恰巧此时算法分析与设计一课有一个空位，我就改选了算法分析与设计。实用算法设计一课使用的是《程序员实用算法》一书，说实在的，里面的例子都是经过精心编写的算法，非常优美，很多细节处理的十分精妙，可惜我还是更喜欢算法分析与设计一课。算法分析与设计使用的教材是经典的《算法导论》一书，整个课程跳过了一些简单的章节，但是覆盖到了算法导论中的大部分章节（不含第七部分和第八部分）。这课说实在的，超赞啊！我本科学的算法课用的是《算法概论》一书，比较偏重于算法设计，《算法导论》则是设计与分析并重。自己看《算法导论》的时候真心看不进去，这门课程一口气跟下来觉得并不吃力，而且有一种融会贯通的感觉。发现很多的时候，一个算法的时间复杂度暗示了其设计思想。例如，含lg&lt;em&gt;n&lt;/em&gt;的往往是用了递归、二分或者操作时间复杂度为lg&lt;em&gt;n&lt;/em&gt;的数据结构；而&lt;em&gt;n&lt;/em&gt;&lt;sup&gt;1/2&lt;/sup&gt;或者是更奇怪的常数&amp;alpha;作为指数的算法往往是多级算法，分阶段算法，或者待定参数的算法，&amp;alpha;是最后接触的最优参数。一些以前不能够很好的理解的数据结构，比如说线段树，也得到了很好地理解。美中不足的是红黑树的部分讲解依然比较混乱，老师没有采用《算法导论》一书中的红黑树的讲解，而是从其他方面讲解的红黑树，感觉仍然不够理想。恰巧以前看到过&lt;a href="http://mindhacks.cn/"&gt;刘未鹏&lt;/a&gt;的&lt;a href="http://mindhacks.cn/2008/07/07/the-importance-of-knowing-why/"&gt;《知其所以然（以算法学习为例）》&lt;/a&gt;中提到了&lt;a href="http://www.cs.princeton.edu/%7Ers/talks/LLRB/RedBlack.pdf"&gt;Left-Leaning Red Black Tree&lt;/a&gt;，仔细的看了5次以上后，终于觉得能够明白红黑树是怎么一回事儿了。&lt;/p&gt;&lt;p&gt;数学课我选择了组合数学并且旁听随机过程。组合数学用的是Brualdi的&lt;em&gt;&lt;a href="http://www.amazon.com/Introductory-Combinatorics-3rd-Richard-Brualdi/dp/0131814885"&gt;Introductory Combinatorics&lt;/a&gt;&lt;/em&gt;，课上老师基本上把整本书讲了一遍，作业题中不乏一些难度较高的证明题。上这门课的感觉还是很多问题都似曾相识，比如说经典的八皇后问题，这些问题以前在遇到的时候都是采用一些固定的策略来进行处理，并不知道为什么要采用这样的策略。这门课程让我认识到了三类基本问题：组合计数、组合优化、组合设计，每一类问题都有很多数学工具来对其进行分析和解决。顺便说一下，书中对于如何构造GF(&lt;em&gt;p&lt;sup&gt;k&lt;/sup&gt;&lt;/em&gt;)讲解的实在是让人有点稀里糊涂的，恰巧我另一门课程密码学及其应用中讲到了这些内容，让我在这点上没有稀里糊涂的跳过去。随机过程是一门神奇的课，说实在的，我一直都挺怕概率论的，我觉得概率论十分的违反直觉，很多时候得出的答案都令我十分费解，也不能够肯定是否正确。随机过程这门课的老师非常棒！非常厉害！由于时间精力的关系，我没有做这门课的习题，因此收获相对较小，但是老师在课上提出的很多问题，使我对于概率论的理解深刻了许多。这里举两个我印象比较深刻的例子。（在座的几乎都是男生）你们的爸爸有儿子，你们爸爸的爸爸也有儿子，往上若干代都有儿子，但是你不一定有儿子，你儿子不一定有儿子，这不是很奇怪吗？还有一个是敲金蛋问题，一共有三个金蛋，一个有奖，先让你选择一个金蛋，此时主持人将剩下两个金蛋中没奖的一个砸开，问你是否改变选择？（即改变或者不改变选择，中奖的概率是多少？答案分别是2/3和1/3）这些问题都揭示了概率的基本问题，比如概率是人为规定的，描述可能性的（不确定性的）度量，等等。&lt;/p&gt;&lt;p&gt;中科大还开了一门叫做程序设计与计算机系统的课程，教材用的是经典的&lt;a href="http://csapp.cs.cmu.edu/"&gt;&lt;em&gt;Computer Systems: A Programmer's Perspective&lt;/em&gt;&lt;/a&gt;。这课上得我十分开心啊，说实在的，我大四考完研才开始看这本书，真心觉得相见恨晚啊。看这本书，觉得终于把我学过的计算机组成原理、操作系统、C语言给联系起来了，收获十分的大，更重要的是一种看待问题角度的改变。比如说，以前很难理解为什么位移操作有两种，虽然知道这两种位移操作的概念和区别，但是还是不知道本质的原因，看了这本书之后，就明白了，对于补码表示的数字，需要扩展符号位才能够得到正确的结果。有时候觉得国外真先进，大一的时候就开这门课，我却直到研一了才把这门课给学了；但是又觉得，如果我没有学过计算机组成原理、操作系统、C语言等等课程，没有这么多的累积，学这门课的时候也不会有这么大的收获，有一种茅塞顿开豁然开朗的感觉。这本书，估计还要反复读上3、5遍才能够完全吃透吧。&lt;/p&gt;&lt;p&gt;说到程序设计与计算机系统，就不得不说说我选的课程&amp;mdash;&amp;mdash;计算机病毒与免疫系统，参考教材《程序员的自我修养》。这也是一门神奇的课，实验难度相当高，几乎快比得上我本科学操作系统时实验的难度了。这课其实关键就是对于编译、链接、加载的理解程度。一段病毒代码想要在宿主程序中运行，就需要我们手工来完成编译、链接、加载的工作，在这个基础上，再对病毒程序进行一定的伪装和保护。因此，对于编译、链接、加载的理解程度直接影响了理解这门课程原理的难易程度。病毒和杀毒软件的大部分思想都是十分朴素和平凡的，但是在矛与盾的斗争过程中，总是会擦出新的火花，有些思路巧妙地不禁让人拍案叫绝，例如说代码自定位，字符串的注入等等。病毒和杀毒软件的战场，是一个比拼思维活跃度的地方。这门课程的实验中，大量的使用了汇编代码，让我发现了嵌入汇编的巨大威力，有些地方使用C语言写起来十分的繁琐和枯燥，最主要的是难以阅读和理解，但是用等价的汇编形式来编写，就十分的简介明了，尤其是函数指针的部分，C语言为了进行编译时期检查将函数指针弄得有些太过于繁琐了。从2年前，我就知道要把C语言和汇编语言结合起来看待，看到C语言就应该想到其汇编形式，但是很难做到。这次经过一定量的训练，终于可以勉强做到，看到C程序的时候，在有意识地去想的时候，能够想到这段代码的汇编形式。这有助于我们抛弃一些不必要的tricks，在关键的时候进行优化。（这也是&lt;em&gt;CSAPP&lt;/em&gt;所需要达到的一个目标之一）&lt;/p&gt;&lt;p&gt;说完这两门课程，不妨看看上面提到过的密码学及其应用一课。在上这门课程以前，我一直认为密码学领域主要是一些数学问题，程序员需要关注的内容很少；上了这门课程后，我发现，所有的程序员都应该学习一下密码学的基本知识，走出密码学的误区。在这门课程上，我了解了，即便是有了安全的加密方式，如果使用不当的话，仍然可能会泄密或收到被攻击者伪装成正常消息而受到欺骗，非对称加密并不比对称加密更安全，反而，非对称加密方式由于加密速度较慢，使用范围会受到限制。有些不安全性的引入是十分隐蔽的，而只要有一处不安全的地方，整个体系就好像马其顿防线一样会被整个绕过去，所以我觉得，如果真的对于安全的需求比较高，还是要建立一个从理论上就安全的系统。&lt;/p&gt;&lt;p&gt;高级图形图像处理和现代通信网上的我都相当苦闷了，没有物理基础的我基本上没办法从理论上理解频域这个概念，只能够从直观上进行理解和解释。高级图形图像处理实际上分两部分：图形学、图像处理。这两门课虽然由于缺乏理论基础理解不够深刻，但是如果我今后在这方面深入学习的话，对于我的学习有着指导作用。&lt;/p&gt;&lt;p&gt;面向对象技术一课是针对于本科没有学过C++的同学的。C++我实在是不敢说自己学得多好，C++实在是太复杂了，语言细节非常多。不过我对于C++常用的一部分子集自觉掌握得尚可，于是就跑到了嵌入式课程去听设备驱动开发。也是很基础的东西，比如说如何构建一个Linux驱动程序等等，和硬件接口连接比较紧密，收获并不是太大。&lt;/p&gt;&lt;p&gt;Web安全实践一课主要讲了讲Ruby On Rails，和一些常见的攻击，比如说Cross-site Script，SQL injection之类的，其中一个实验写了个Worm脚本挺有意思的。我本科写了将近3年的网站，ASP.NET，后来发现WebForm模型理解起来确实比较别扭，用起来经常会弄得乱七八糟的，而新出的ASP.NET MVC框架就好得多。ASP.NET MVC框架其实大量的模仿了Rails框架，于是我怀着膜拜的心情上完了这门课程，发现Rails框架确实整合了很多工具进来，而且扩展点留的也恰到好处，的确使得Web开发变成了一件非常愉悦的事情。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;然后？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;然后就跑回北京睡大觉了，发现现在休息是一件很奢侈的事情，突然很有一种紧迫感，觉得有很多东西想学却来不及学。&lt;em&gt;Concrete Mathematics&lt;/em&gt;、&lt;em&gt;SICP&lt;/em&gt;、&lt;em&gt;The Art Of Computer Programming&lt;/em&gt;&amp;hellip;&amp;hellip;下学期必须得选的课就很少了，但是想要学的课却相当多。希望能赶紧把想学的都学会，然后到实践中去大展身手呢。&lt;/p&gt;&lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:714c4b45-6238-4b2c-9078-e3f84e116520" class="wlWriterEditableSmartContent" style="margin: 0px; display: inline; float: none; padding: 0px;"&gt;Technorati 标签: &lt;a href="http://technorati.com/tags/%e4%b8%ad%e7%a7%91%e5%a4%a7" rel="tag"&gt;中科大&lt;/a&gt;,&lt;a href="http://technorati.com/tags/%e6%80%bb%e7%bb%93" rel="tag"&gt;总结&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/HCOONa/aggbug/2329372.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/HCOONa/archive/2012/01/25/summary-in-USTC-fist-stage.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/HCOONa/archive/2012/01/24/a-simple-interview-problem.html</id><title type="text">说说一个简单的面试题</title><summary type="text">过节了终于有时间写写东西了，有些东西不记录下来就会一点点忘掉。 前几天去面试，有一道题我回答的不太令自己满意，回来之后思索了一下，又想到了一些东西，记录一下。 简单问题？ 题目就是简单的反转单向...</summary><published>2012-01-24T11:29:00Z</published><updated>2012-01-24T11:29:00Z</updated><author><name>HCOONa</name><uri>http://www.cnblogs.com/HCOONa/</uri></author><link rel="alternate" href="http://www.cnblogs.com/HCOONa/archive/2012/01/24/a-simple-interview-problem.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/HCOONa/archive/2012/01/24/a-simple-interview-problem.html"/><content type="html">&lt;p&gt;过节了终于有时间写写东西了，有些东西不记录下来就会一点点忘掉。&lt;/p&gt;&lt;p&gt;前几天去面试，有一道题我回答的不太令自己满意，回来之后思索了一下，又想到了一些东西，记录一下。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;简单问题？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;题目就是简单的反转单向链表。&lt;/p&gt;&lt;p&gt;我很快给出了一段代码：&lt;/p&gt;&lt;fieldset&gt;&lt;span style="color: blue;"&gt;void &lt;/span&gt;reverse_chain(Node *h)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;if&lt;/span&gt;(!h || !h-&amp;gt;next) &lt;span style="color: blue;"&gt;return &lt;/span&gt;;&lt;br/&gt;    Node *previous = NULL,&lt;br/&gt;         *current  = h,&lt;br/&gt;         *next     = h-&amp;gt;next;&lt;br/&gt;    &lt;span style="color: blue;"&gt;while&lt;/span&gt;(next) {&lt;br/&gt;        current-&amp;gt;next = previous;&lt;br/&gt;        previous = current;&lt;br/&gt;        current  = next;&lt;br/&gt;        next     = next-&amp;gt;next;&lt;br/&gt;    }&lt;br/&gt;    current-&amp;gt;next = previous;&lt;br/&gt;    h-&amp;gt;next = NULL;&lt;br/&gt;}&lt;/fieldset&gt;&lt;p&gt;这段代码显然是有问题的，它没有返回反转后的链表的头指针，只需在最后加上一句 &lt;span style="color: blue;"&gt;return &lt;/span&gt;current; 即可。比较理想的代码如下所示：&lt;/p&gt;&lt;fieldset&gt;Node * reverse_chain(Node *h)&lt;br/&gt;{&lt;br/&gt;    &lt;span style="color: blue;"&gt;if&lt;/span&gt;(!h || !h-&amp;gt;next) &lt;span style="color: blue;"&gt;return &lt;/span&gt;h;&lt;br/&gt;    Node *previous = NULL,&lt;br/&gt;         *current  = h,&lt;br/&gt;         *next     = h-&amp;gt;next;&lt;br/&gt;    &lt;span style="color: blue;"&gt;while&lt;/span&gt;(next) {&lt;br/&gt;        current-&amp;gt;next = previous;&lt;br/&gt;        previous = current;&lt;br/&gt;        current  = next;&lt;br/&gt;        next     = next-&amp;gt;next;&lt;br/&gt;    }&lt;br/&gt;    current-&amp;gt;next = previous;&lt;br/&gt;    h-&amp;gt;next = NULL;&lt;br/&gt;    &lt;span style="color: blue;"&gt;return &lt;/span&gt;current;&lt;br/&gt;}&lt;/fieldset&gt;&lt;p&gt;&lt;strong&gt;复杂问题？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;接下来，面试官问了我一个问题：可不可以只使用两个指针，完成单向链表的反转？&lt;/p&gt;&lt;p&gt;我思索了一段时间，认为不能够只使用两个指针完成单向链表的反转。理由是这样的，反转单向链表的过程，需要将当前节点指向前一个节点，这里需要两个指针，因为前一个节点的指针已经指向了更前一个节点；完成这一动作后，需要继续处理下面的节点，因此还需要能够索引到下一个节点；这样，一共需要三个指针。（我还特意向面试官询问了，是否考虑在调用栈上保存信息的情况，即使用递归算法）&lt;/p&gt;&lt;p&gt;其实这个答案是正确的。但是面试官一再强调，一定可以只使用两个指针完成单向链表的反转。于是我向面试官请求一些提示。&lt;/p&gt;&lt;p&gt;面试官给出了这样的提示：如果像这样每次处理完一个节点后向后移动一个节点继续处理，则需要三个指针；如果不是采用向后移动的方式，是否有可能采用更少的指针？譬如说每次都将下一个节点插入到链表头部。&lt;/p&gt;&lt;p&gt;每次将当前节点从链表中取下插入到链表头部似乎仍然需要3个指针：一个指向表头，一个指向当前节点，一个指向当前节点的上一个节点。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/HCOONa/201201/201201241928588252.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border-width: 0px;" title="图表1" src="http://images.cnblogs.com/cnblogs_com/HCOONa/201201/201201241928589581.png" alt="图表1" width="459" height="197" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p align="center"&gt;图1：将当前节点插入到链表头反转单向链表示意图。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;最后终于想到了利用原来链表头的next域来存储Previous节点的方法。&lt;/p&gt;&lt;p&gt;面试官友善的说道，最终原来链表头的next域是要指向Nil的，因此利用原来链表头的next域进行存储是一种很自然的想法。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;无意义问题？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;说实在的，这个链表反转的方法实际上还是用了3个指针，可以说一开始我就没走到面试官所希望我想到的东西的道路上。实际上，我内心深处还是颇为不赞同这样一种方式的，因为这个反转链表的方法有效率上的问题：即如何快速的访问原来链表头的next域？如果为此引入一个指针的话，就实际上需要4个指针，比原来的方法还要多出来一个；否则就需要遍历O(n)的链表才能够发现原来链表头的next域，时间复杂度上得不偿失。&lt;/p&gt;&lt;p&gt;并且，实际上使用了3个指针还是2个指针，在C程序编译完后，实际上只是对应着使用了3个寄存器还是2个寄存器，本质上并没有时空性能上的提升，还为此付出了额外的代码复杂度，实在是没有什么意义。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;所以？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;所以其实这个问题就是没什么意义，面试官对于问题的描述和引导也做得不好，但是对于这一问题所带来的新的思路，确实令我思索了很久。有的时候，我就是在做一些没有意义的事情，但是探索过程本身，却能给我带来很大的乐趣和价值。&lt;/p&gt;&lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:7474ca02-8eb3-4b6e-8760-86f143eb942a" class="wlWriterEditableSmartContent" style="margin: 0px; display: inline; float: none; padding: 0px;"&gt;Technorati 标签: &lt;a href="http://technorati.com/tags/%e9%9d%a2%e8%af%95" rel="tag"&gt;面试&lt;/a&gt;,&lt;a href="http://technorati.com/tags/C" rel="tag"&gt;C&lt;/a&gt;,&lt;a href="http://technorati.com/tags/%e9%93%be%e8%a1%a8" rel="tag"&gt;链表&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/HCOONa/aggbug/2329214.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/HCOONa/archive/2012/01/24/a-simple-interview-problem.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/HCOONa/archive/2011/11/09/I-love-study.html</id><title type="text">我爱学习，你呢？</title><summary type="text">今天看到有个小MM抱怨高数难，不免有些感慨。 现在很多课程把本来十分快乐的事情变得不再快乐，让我看的痛心疾首，亲身经历的苦不堪言。学习本是一件很快乐的事情。 我从小就是一个让所有老师又爱又恨的孩子——我几乎上课从来不听课，但偏偏什么都会，而且考试成绩还不错。我不喜欢听课，一方面是因为上课讲的东西我都知道了，另一方面是上课讲的好没意思，远没有一些趣题吸引我。我不听课但成绩还上课的原因，多半是因为我喜欢那些所谓的奥数、奥物等题。这些题有难度，但是也很有意思，不断的吸引着我主动的去从我能达到的渠道中获取足够我解开这道难题的知识。直到上大学前，这都是我学习的直接动力。 我一直很庆幸，...</summary><published>2011-11-08T17:09:00Z</published><updated>2011-11-08T17:09:00Z</updated><author><name>HCOONa</name><uri>http://www.cnblogs.com/HCOONa/</uri></author><link rel="alternate" href="http://www.cnblogs.com/HCOONa/archive/2011/11/09/I-love-study.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/HCOONa/archive/2011/11/09/I-love-study.html"/><content type="html">&lt;p&gt;    今天看到有个小MM抱怨高数难，不免有些感慨。 现在很多课程把本来十分快乐的事情变得不再快乐，让我看的痛心疾首，亲身经历的苦不堪言。学习本是一件很快乐的事情。&lt;/p&gt;&lt;p&gt;   我从小就是一个让所有老师又爱又恨的孩子——我几乎上课从来不听课，但偏偏什么都会，而且考试成绩还不错。我不喜欢听课，一方面是因为上课讲的东西我都知道了，另一方面是上课讲的好没意思，远没有一些趣题吸引我。我不听课但成绩还上课的原因，多半是因为我喜欢那些所谓的奥数、奥物等题。这些题有难度，但是也很有意思，不断的吸引着我主动的去从我能达到的渠道中获取足够我解开这道难题的知识。直到上大学前，这都是我学习的直接动力。&lt;/p&gt;&lt;p&gt;    我一直很庆幸，庆幸我所走的这条道路上没有人指引我。很残酷但很现实，也是比较容易招人骂的原因是，我上大学前所遇到的人中，没有一个人既有时间又有能力在这条路上给我恰到好处的指引。比起书本上所能见到的常规的题目，奥数题非常的不同，它必须要你绞尽脑汁的思考后，才能够得出答案。与之成反比的则是书上的常规题，非常显然，只要把前面的定理、公式直接一应用就能直接得出答案。这样的题抑制了我们探索的好奇心，使得我们失去对于知识的索求。而奥数题则不同，虽然还是这些知识，但总是要你仔细的思索很久，然后在不经意间擦出一些思维的火花，照亮出解开这道密题的真正道路。这样一个过程，正是我们遇到一个新问题时，真正去试图解决它的一个过程。很多人从小就失去了这一解题的能力和乐趣。&lt;/p&gt;&lt;p&gt;   我一直觉得学习是快乐的。 每一次学到新的知识，都让我觉得有一种发现了新大陆一般的惊喜。运用新的知识，我可以解决一类新的问题，我确实觉得自己比以前强大了很多。以前让我束手无策、抓耳挠腮的问题，在新的我面前全然是小菜一碟，这种感觉真的是很令我感到满足。而每一次对旧有知识的新发现，都让我感到额外的惊喜。就好比你隔了几年看到你的初恋，发现他/她长大后又向你展示了更美的一面。&lt;/p&gt;   &lt;p&gt;我还十分乐于将这种快乐分享给其他人。每当有人问我问题时，我都很开心，并且愿意将我如何思考这一问题的思路，以及对所用到的知识的理解，都完完整整的告诉他。 但是很少有人愿意像我一样，乐于完完整整的看清这些知识的本来面目——他们只是想尽快得到这一问题的答案。这让我觉得十分可惜，进而让我更愤恨我们至今为止所接受的教育——它不仅剥夺了大家学习的快乐，还剥夺了我与大家分享这种快乐的可能性。&lt;/p&gt;    &lt;p&gt;你觉得学习快乐吗？&lt;/p&gt;&lt;img src="http://www.cnblogs.com/HCOONa/aggbug/2241896.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/HCOONa/archive/2011/11/09/I-love-study.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/HCOONa/archive/2011/05/17/2049221.html</id><title type="text">回首在哈工大软件学院本科四年的学习生活</title><summary type="text">帽子 不知道在哪儿看见这样一句话，深有感触：现在回想自己的大学，我只能引用费正清在《伟大的中国革命》中说的‘这锅汤熬得还不错，就这样吧’。在哈工大大学四年下来，真正有时间自己看看书、锻炼锻炼身体，也就只有大一和大四的时候有这样的时间；大二逃课泡妞，以至于挂了不少科，现在想来却只觉得有舍有得，舍了保研的机会，得到了难得的年少轻狂；大三的时候忙的四脚朝天，除了弥补大二不好好学习，大三好好学以外，也有着...</summary><published>2011-05-17T11:47:00Z</published><updated>2011-05-17T11:47:00Z</updated><author><name>HCOONa</name><uri>http://www.cnblogs.com/HCOONa/</uri></author><link rel="alternate" href="http://www.cnblogs.com/HCOONa/archive/2011/05/17/2049221.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/HCOONa/archive/2011/05/17/2049221.html"/><content type="html">&lt;p&gt;&lt;strong&gt;帽子&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;不知道在哪儿看见这样一句话，深有感触：现在回想自己的大学，我只能引用费正清在《伟大的中国革命》中说的‘这锅汤熬得还不错，就这样吧’。在哈工大大学四年下来，真正有时间自己看看书、锻炼锻炼身体，也就只有大一和大四的时候有这样的时间；大二逃课泡妞，以至于挂了不少科，现在想来却只觉得有舍有得，舍了保研的机会，得到了难得的年少轻狂；大三的时候忙的四脚朝天，除了弥补大二不好好学习，大三好好学以外，也有着俱乐部的活动，以及自己想做一番东西出来的想法，可惜终究弄得不能令自己满意。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;大一：&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;上半学期课程：军训及军事理论、大学英语、体育、高等数学、线性代数、程序设计语言、数字逻辑、计算机导论、计算机职业道德&lt;/p&gt;  &lt;p&gt;下半学期课程：大学英语、体育、中国特色社会主义理论、高等数学、离散数学、交流技巧、个体软件过程(PSP)、计算机组成技术、C++程序设计语言&lt;/p&gt;  &lt;p&gt;现在想来，我大一的时候以逃课玩游戏，做ACM题为主，实在是有点浪费时间，不过以当时的经历、眼界等等来看，这样做也还说得过去。&lt;/p&gt;  &lt;p&gt;下面说说我对当时上的这些课程的一些看法和补充。&lt;/p&gt;  &lt;p&gt;军训、大学英语、体育、计算机职业道德、政治自不必多说。&lt;/p&gt;  &lt;p&gt;高等数学最开始会和高中所学的高等数学初步有所重叠，但是接下来的积分部分可以说是整个高等数学的基础，如果在这时候不多做些题，不好好听听课，等到以后想弥补就比较困难了。当初给我们上课的是刘维国老师，刘老师讲的课非常的棒，希望大一的同学们不要重蹈覆辙，高数一定要好好上。另外咱们学院的高等数学用的是哈工大出版社的《工科数学分析》，这是一本非常难的教材，建议同学们使用同济数学系的《高等数学》作为辅助教材。另外就是，一定要多做题，反正老师给发的题都按时做了就没问题！&lt;/p&gt;  &lt;p&gt;线性代数在图形学中应用非常的多，大一的时候讲的也比较简单，算是一门非常好过的科目了。&lt;/p&gt;  &lt;p&gt;程序设计语言讲的就是C语言，我去上的很少，因为很早之前就能比较熟练的使用C语言了。C语言语法元素非常的少，所以整个语言也显得非常简单。我不清楚现在是否还是使用谭浩强的《C语言程序设计》作为教程，但是我觉得这本书并不应该作为我们的教材，另外老师讲的很多部分有可能都不符合ANSI C的标准，这点我不想做过多的评价。推荐教材K&amp;amp;R的《The C programming Language》和Robert Sedgewick的《Algrithms in C》，这两部书都有中文版并且在一区的图书馆中都有，二区就不太清楚了，不行就跑一趟吧。头一本书估计不会看太久，第二本书可能看起来比较困难，推荐多做练习，我觉得NOIP的比赛题中挑选比较简单的题做做就好。另外我不推荐在Windows下面写C程序玩，因为C语言本来就是为了开发Unix系统弄出来的东西，咱们要玩也就玩个原汁原味的，不妨装个Windows、Ubuntu双系统，没事鼓捣鼓捣Ubuntu，学学Makefile，在Linux下面编写C程序，很有Geek的感觉呢。&lt;/p&gt;  &lt;p&gt;因为C语言实在是比较重要的一门语言，所以我在这里花费了非常多的篇幅来写这些东西。但是我觉得把C语言作为自己的第一门语言还是有点#$@#%@!$。所以如果有空的话，不妨看一看MIT的公开课，跟着视频学学Python也很不错，还能顺便练练英语。&lt;/p&gt;  &lt;p&gt;关于数字逻辑这门课，我本身很不感冒，不过对于了解计算机的最终原理还是有帮助的……推荐辅助教材《Code》（中文名《编码的奥秘》）&lt;/p&gt;  &lt;p&gt;计算机导论这门课讲的#$@!%，我也不多说什么了，推荐教材《New Perspectives on Computer Concepts》（中文名《计算机文化》）和MIT公开课中的计算机导论。&lt;/p&gt;  &lt;p&gt;离散数学是对于计算机科学比较重要的一门课程，不过其中的现代代数部分据说不太重要@_@总之好好学没坏处，哈哈。推荐后续教材《组合数学》、《Concrete Mathematics》（中文名《具体数学》）&lt;/p&gt;  &lt;p&gt;交流技巧是一门外教课，现在应该是换老师了，不知道情况如何，这这门课上尽量多说话吧：P&lt;/p&gt;  &lt;p&gt;个体软件过程(PSP)是一门标准的软件工程的专业课，在我看来算是我软件工程的启蒙课程，个人认为非常重要。这一方向我不能给出更多的指引。推荐辅助读物《人月神话》、《走出软件作坊》、《人件》、高德拉特的《目标》、《观止——微软创建NT和未来的夺命狂奔》、《梦断代码》、《敏捷软件开发——原则、模式与实践》、《重构：改善既有代码的设计》、《代码整洁之道》、《设计模式——可复用面向对象软件的基础》。这些书是我对所有软件工程方向的推荐读物，不是针对PSP的。&lt;/p&gt;  &lt;p&gt;计算机组成原理这门课也是考研的课程之一。推荐辅助教材：《Intel微处理器》、《Computer Systems: A Programmer's Perspective》（中文名《深入理解计算机系统》）。这本推荐教材一定要读，不读白学计算机组成原理了。&lt;/p&gt;  &lt;p&gt;C++程序设计语言这门课课时太少，基本上什么都没讲明白，主张自学，推荐教材《Accelerated C++》、《The C++ Programming Language》、《The C++ Standard Library: A Tutorial and Reference》（中文名《C++沉思录》）、《C++ Coding Standards: 101 Rules, Guidelines, and Best Practices》（中文名《C++编程规范:101条规则、准则与最佳实践》）&lt;/p&gt;  &lt;p&gt;大一是我大学生活中最宝贵的时光，也是浪费时间最多的一段时期：P&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;大二：&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;上半学期课程：大学英语、马克思主义哲学、数据结构课程设计、概率论与数理统计、软件工程概论、数据结构与算法、Java语言、操作系统、市场营销、IT企业管理、体育、软件开发工具&lt;/p&gt;  &lt;p&gt;下半学期课程：数据库课程设计、软件开发过程管理、数据库系统、计算机网络、软件构件与中间件技术、.Net、财务管理、知识产权法、体育、英语口语、面向对象技术与UML、运筹学概论&lt;/p&gt;  &lt;p&gt;大二是我自己上的比较混乱的一年，不过好在下半学期专业课比较多，上着还比较有意思。&lt;/p&gt;  &lt;p&gt;数据结构与算法我那年是黄院长讲的，讲的#$@%#@!……不过内容都很基础，不知道有什么可推荐的教材，好好看看书就好了，关键还是多练习。数据结构如何实现如果记不住的话，至少要把这个数据结构的特点、什么时候用、有什么优势记住。也就是说，知道有这么个东西，知道什么时候用就好。补充一下，最近看到了《程序员实用算法》，似乎不错（作为一个入门书籍）&lt;/p&gt;  &lt;p&gt;概率论是陈桂林老师讲的，这门课也是考研要考的课之一，陈老师讲的挺好的，好好听课，按时做作业就行。&lt;/p&gt;  &lt;p&gt;软件工程方面推荐的书籍在上面写PSP的时候就写过了，估计都看完了也就差不多了。&lt;/p&gt;  &lt;p&gt;Java语言讲的是够慢的，这个语言比起C++那是简单不少了，直接看看《Java核心技术》第一册就好了，然后去支持Java的OJ平台上做做ACM的题。从思想上讲要从面向过程转向面向对象，这一点是比较困难的，我没法提供好的建议，不过建议多看看上面提到过的《敏捷软件开发——原则、模式与实践》&lt;/p&gt;  &lt;p&gt;操作系统当年是孙志刚老师教的，特点就是比较累，但是能学到很多知识，前提是你按照他要求去做。推荐教材《Linux内核完全剖析》、《深入理解计算机系统》、《操作系统概念》。这门课是我觉得最接近MIT公开课水平的一门课了！&lt;/p&gt;  &lt;p&gt;市场营销和IT企业管理……我只能说建议留好课件……&lt;/p&gt;  &lt;p&gt;软件开发工具讲的是用Eclipse开发网站，这个，你要是不会就去听听，要是会了就算了吧……或者找个教程自学也行我觉得，课时这么长，不如好好讲讲Java高级特性。&lt;/p&gt;  &lt;p&gt;数据库系统讲的比较浅的内容，但是也非常难了，建议没事多看看书，反正我觉得挺难的。&lt;/p&gt;  &lt;p&gt;计算机网络也是考研课，也挺难，而且非常枯燥，虽然最后考试挺简单的，但是仍然建议好好学、认真学，毕竟以后做的东西跟网络肯定分不开。可能还会涉及到一些通讯原理方面的知识，推荐《数据与计算机通信》，这本书大四上数据与计算机通信的时候还会用。&lt;/p&gt;  &lt;p&gt;软件构建与中间件讲的都是中间件技术，可能对遗留系统会比较有意义，再有就是Windows下的COM+组件开发 ，这方面我没有发言权，留给大家补充吧。&lt;/p&gt;  &lt;p&gt;.NET讲的就跟Java一样慢，推荐从网站程序入手自学，推荐教材《ASP.NET 第一步》、《ASP.NET揭秘》，推荐社区资源博客园(www.cnblogs.com)。&lt;/p&gt;  &lt;p&gt;面向对象与UML是个老奶奶级别的老师讲的，内容非常多，但是讲的可能比较枯燥，不过仍然强烈建议好好听课！讲的非常好的，同样推荐《敏捷软件开发——原则、模式与实践》和《设计模式》。&lt;/p&gt;  &lt;p&gt;运筹学还是陈桂林老师讲的，内容也比较浅，有兴趣的同学可以深入学习，推荐教材《数学建模》、《最优化方法》。&lt;/p&gt;  &lt;p&gt;大二下学期是我真正开始好好学习的时期，我想说的是，无论什么时候意识到学习的重要性都不晚，只是你需要从此开始投入大量的精力进行学习，你所需要的就是坚持、毅力，成功离你并不远。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;大三：&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;上半学期课程：软件工程课程设计、软件项目管理、软件质量保证与测试、软件能力成熟度模型CMMI、编译原理、用户界面设计、合同法、商务谈判、英语口语、分布式系统、J2EE、面向服务的计算&lt;/p&gt;  &lt;p&gt;下半学期课程：综合课程设计、系统分析与设计、计算机图形学、信息检索、算法设计与分析初步、IT企业创业管理、企业资源计划、企业与服务建模、供应链与客户关系管理、服务管理（含IT服务管理）、服务工程综合实践、服务学概论&lt;/p&gt;  &lt;p&gt;大三是我印象中最忙碌的一年，现在想来也不知道都忙点什么了= =，好像主要是排课没排好，各种惨…… &lt;/p&gt;  &lt;p&gt;软件质量保证与测试我觉得是一门挺好的课，但是可能有些人会觉得有些枯燥，我主要考虑的还是自动化测试以及集成自动化、持续测试等等问题，所以觉得比较好玩，有很多值得思考的地方。&lt;/p&gt;  &lt;p&gt;CMMI这课上的最惨了，没有能讲这课的老师= =，推荐自学。推荐教材：《基于软件能力成熟度模型(CMM)的软件过程改进:方法与实施》、《CMMI成功项目管理——7个CMMI过程域》 &lt;/p&gt;  &lt;p&gt;编译原理是一门比较难的课，除了教师推荐的“龙书”（编译原理，买本科教学版就够）以外，还推荐《现代编译原理——c语言描述》、《程序员的自我修养—链接、装载与库》、《程序设计语言：实践之路》&lt;/p&gt;  &lt;p&gt;用户界面设计我觉得是非常好的一门课，因为大多数程序员好像都不怎么关心用户界面设计：P其实用户界面的重要性大家都知道，就是觉得有点无从下手的感觉，这门课使得我开始注意、并且追求用户界面设计。&lt;/p&gt;  &lt;p&gt;面向服务的计算看起来比较深奥，其实主要还是讲WebService和SOA的，还讲了BPMN工作流等等。老师很牛，不过我上这门课的时候这个老师才讲第一次课……&lt;/p&gt;  &lt;p&gt;下半学期可以自己选方向，我选的是服务学方向。多媒体方向比较难但是比较容易通过，嵌入式方向非常惨，又难又不好过工作量也大，服务学方向比较好过，但是工作量也比较大，网络方向不太清楚，据说也不太容易。想要校外实习的同学这时候就应该好好准备了，多看看算法什么的，做做ACM，把C语言的边边角角都看看。&lt;/p&gt;  &lt;p&gt;大三好像主要是忙俱乐部的事来着，后来觉得还是留下了很多遗憾╮(╯▽╰)╭&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;大四：&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;上半学期课程：数据与计算机通信、搜索引掣技术&lt;/p&gt;  &lt;p&gt;下半学期课程：&lt;/p&gt;  &lt;p&gt;大四忙着考研，结果还不算理想，不过也还不错。考研比高考还是容易太多了，主要是心理压力要小得多，咱们这个专业找工作难度还是比较低的：D准备考400分的同学最好早早的就复习，天天都往死里拼，要不然还是比较困难的。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;尾巴&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;流水账似的记了这么多，回忆了一下大学四年的学习生活，以此为低年级的同学做一些不靠谱的指引，并且缅怀一下这四年的生活。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;附加资源：&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;资料集中地：&lt;/p&gt;  &lt;p&gt;维基百科、谷歌（百度真没法比）、图书馆、知网、万方、博客园、ItEye、CSDN、学院FTP、run.hit.edu.cn、MIT公开课&lt;/p&gt;  &lt;p&gt;用户体验：&lt;/p&gt;  &lt;p&gt;秋叶的个人博客，http://www.70man.com/&lt;/p&gt;  &lt;p&gt;UCD大社区- 以用户为中心的设计，http://ucdchina.com/&lt;/p&gt;  &lt;p&gt;数学：&lt;/p&gt;  &lt;p&gt;Matrix 67，http://www.matrix67.com/blog/&lt;/p&gt;&lt;img src="http://www.cnblogs.com/HCOONa/aggbug/2049221.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/HCOONa/archive/2011/05/17/2049221.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/HCOONa/archive/2011/04/28/2031830.html</id><title type="text">我对编程语言的一些看法</title><summary type="text">各个编程语言都是图灵兼容的，因此其能力从数学而言是一致的。 我所在意的是编程语言的抽象能力、表述能力。 表述能力好的语言，看起来比较简单，但是从实质上讲是比较容易理解。这意味着用这种语言编写的代码会比较容易理解，并不意味着用这种语言进行开发会比用其他语言开发更容易。因为要做的事还是一定的，我们只是换了一种语言进行表述而已。做这件事本身的难度并不会因为我们换了一种语言而增加或减少。相反的，我们用一种...</summary><published>2011-04-28T07:27:00Z</published><updated>2011-04-28T07:27:00Z</updated><author><name>HCOONa</name><uri>http://www.cnblogs.com/HCOONa/</uri></author><link rel="alternate" href="http://www.cnblogs.com/HCOONa/archive/2011/04/28/2031830.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/HCOONa/archive/2011/04/28/2031830.html"/><content type="html">&lt;p&gt;各个编程语言都是图灵兼容的，因此其能力从数学而言是一致的。&lt;/p&gt;  &lt;p&gt;我所在意的是编程语言的抽象能力、表述能力。&lt;/p&gt;  &lt;p&gt;表述能力好的语言，看起来比较简单，但是从实质上讲是比较容易理解。这意味着用这种语言编写的代码会比较容易理解，并不意味着用这种语言进行开发会比用其他语言开发更容易。因为要做的事还是一定的，我们只是换了一种语言进行表述而已。做这件事本身的难度并不会因为我们换了一种语言而增加或减少。相反的，我们用一种表述能力较强的语言来编写代码，可能单位时间内要实现更多的功能。从这一点来看，用“较容易”的语言编写程序，反而是一种更加困难的事情。&lt;/p&gt;  &lt;p&gt;当然，上面说的都是一些理想情况，即我们编写的代码完全没有错误。一旦出现错误，使用表述能力强的语言由于其更容易理解，所以也更容易修复缺陷。也就是说，使用“较容易”的语言所需要的排除缺陷的能力稍弱一些。&lt;/p&gt;  &lt;p&gt;有这样一个现象，即C/C++语言的“专家”比C#的“专家”更“牛”一些，我认为这是由于使用这两种语言的领域不同所导致的，前两者更倾向于开发系统应用，因此对于计算机的理解通常要更深一些，而后者更倾向于做企业开发，因此对于架构方面的认识更深一些。&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;只是对我思考的一些零碎的记录，欢迎拍砖&lt;/p&gt;&lt;img src="http://www.cnblogs.com/HCOONa/aggbug/2031830.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/HCOONa/archive/2011/04/28/2031830.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/HCOONa/archive/2010/09/11/a-beautiful-gnome-theme-elegant-gnome.html</id><title type="text">一个Gnome中的漂亮主题包</title><summary type="text">找到了一个十分精美的gnome主题包，适用于ubuntu和archlinux</summary><published>2010-09-11T06:25:00Z</published><updated>2010-09-11T06:25:00Z</updated><author><name>HCOONa</name><uri>http://www.cnblogs.com/HCOONa/</uri></author><link rel="alternate" href="http://www.cnblogs.com/HCOONa/archive/2010/09/11/a-beautiful-gnome-theme-elegant-gnome.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/HCOONa/archive/2010/09/11/a-beautiful-gnome-theme-elegant-gnome.html"/><content type="html">&lt;p&gt;参考链接：&lt;/p&gt;&lt;p&gt;&lt;a href="http://wowubuntu.com/elegant_theme.html"&gt;http://wowubuntu.com/elegant_theme.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://gnome-look.org/content/show.php/Elegant+Gnome+Pack?content=127826"&gt;http://gnome-look.org/content/show.php/Elegant+Gnome+Pack?content=127826&lt;/a&gt;&lt;/p&gt;&lt;p&gt;截图：&lt;/p&gt;&lt;p&gt;&lt;img height="900" width="1440" src="http://gnome-look.org/CONTENT/content-pre1/127826-1.jpg" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img height="707" width="1015" src="http://gnome-look.org/CONTENT/content-pre2/127826-2.jpg" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img height="900" width="1440" src="http://gnome-look.org/CONTENT/content-pre3/127826-3.jpg" /&gt;&lt;/p&gt;&lt;p&gt;使用说明见前两个网址。其中第二个网址中还含有配套该主题包的chrome、smplayer、firefox主题等等。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/HCOONa/aggbug/1823940.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/HCOONa/archive/2010/09/11/a-beautiful-gnome-theme-elegant-gnome.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/HCOONa/archive/2010/08/22/enable-permalink-for-wordpress-3-in-nginx.html</id><title type="text">Nginx支持WordPress3.0.1的永久链接(Permalink)</title><summary type="text">我最近准备使用Nginx+php-fpm搭建WordPress平台。安装完成后准备启用友好形式的永久链接，但是经过种种尝试和查资料后，都不能成功。Nginx没有Apache特有的mod_rewrite，因此不能由WordPress自动配置。查资料时发现网上流传广泛的解决方案都不管用。下面给出我的解决方案。首先参照Apache2的.htaccess文件：翻译成Nginx的rewrite规则如下：已经...</summary><published>2010-08-22T14:01:00Z</published><updated>2010-08-22T14:01:00Z</updated><author><name>HCOONa</name><uri>http://www.cnblogs.com/HCOONa/</uri></author><link rel="alternate" href="http://www.cnblogs.com/HCOONa/archive/2010/08/22/enable-permalink-for-wordpress-3-in-nginx.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/HCOONa/archive/2010/08/22/enable-permalink-for-wordpress-3-in-nginx.html"/><content type="html">&lt;p&gt;我最近准备使用Nginx+php-fpm搭建WordPress平台。&lt;/p&gt;&lt;p&gt;安装完成后准备启用友好形式的永久链接，但是经过种种尝试和查资料后，都不能成功。&lt;/p&gt;&lt;p&gt;Nginx没有Apache特有的mod_rewrite，因此不能由WordPress自动配置。&lt;/p&gt;&lt;p&gt;查资料时发现网上流传广泛的解决方案都不管用。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;下面给出我的解决方案。&lt;/p&gt;&lt;p&gt;首先参照Apache2的.htaccess文件：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;RewriteEngine On&lt;br/&gt;RewriteBase /wordpress/&lt;br/&gt;RewriteRule ^index\.php$ - [L]&lt;br/&gt;&lt;br/&gt;RewriteCond %{REQUEST_FILENAME} !-f [OR]&lt;br/&gt;RewriteCond %{REQUEST_FILENAME} !-d&lt;br/&gt;RewriteRule . /wordpress/index.php [L]&lt;br/&gt;&lt;/div&gt;&lt;p&gt;翻译成Nginx的rewrite规则如下：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;location /wordpress/ {&lt;br/&gt;    rewrite ^index\.php$ - last;&lt;br/&gt;&lt;br/&gt;    if ( !-e $request_filename ) {&lt;br/&gt;            rewrite . /wordpress/index.php last;&lt;br/&gt;    }&lt;br/&gt;}&lt;/div&gt;&lt;p&gt;已经经过实践验证了。:-)&lt;/p&gt;&lt;img src="http://www.cnblogs.com/HCOONa/aggbug/1805975.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/HCOONa/archive/2010/08/22/enable-permalink-for-wordpress-3-in-nginx.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/HCOONa/archive/2010/08/01/1789777.html</id><title type="text">使用Graphviz绘制用例图</title><summary type="text">Technorati 标签: Graphviz,UML 摘要 Graphviz是一个非常强大的，描述式的图形绘制工具。使用Graphviz绘制关系图形非常的容易和简便，修改起来也十分容易。通常我们都使用Visio或者一些Case工具绘制用例图，但是这些工具修改用例图的时候都比较麻烦。今天，我将给大家介绍如何使用Graphviz绘制用例图，以及使用Graphviz绘制用例图的优势。 下面是维基...</summary><published>2010-08-01T02:02:00Z</published><updated>2010-08-01T02:02:00Z</updated><author><name>HCOONa</name><uri>http://www.cnblogs.com/HCOONa/</uri></author><link rel="alternate" href="http://www.cnblogs.com/HCOONa/archive/2010/08/01/1789777.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/HCOONa/archive/2010/08/01/1789777.html"/><content type="html">&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:2a0a11f5-c437-4a31-9437-a6ef061df248" class="wlWriterEditableSmartContent"&gt;Technorati 标签: &lt;a href="http://technorati.com/tags/Graphviz" rel="tag"&gt;Graphviz&lt;/a&gt;,&lt;a href="http://technorati.com/tags/UML" rel="tag"&gt;UML&lt;/a&gt;&lt;/div&gt;  &lt;p&gt;&lt;strong&gt;摘要&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Graphviz是一个非常强大的，描述式的图形绘制工具。使用Graphviz绘制关系图形非常的容易和简便，修改起来也十分容易。通常我们都使用Visio或者一些Case工具绘制用例图，但是这些工具修改用例图的时候都比较麻烦。今天，我将给大家介绍如何使用Graphviz绘制用例图，以及使用Graphviz绘制用例图的优势。&lt;/p&gt;  &lt;p&gt;下面是&lt;a href="http://en.wikipedia.org" target="_blank"&gt;维基百科&lt;/a&gt;中对于&lt;a href="http://en.wikipedia.org/wiki/Graphviz" target="_blank"&gt;Graphviz&lt;/a&gt;的介绍：&lt;/p&gt; &lt;fieldset style="border-bottom: #ccc 1px solid; border-left: #ccc 1px solid; border-top: #ccc 1px solid; border-right: #ccc 1px solid"&gt;   &lt;p&gt;&lt;b&gt;Graphviz&lt;/b&gt; (short for &lt;i&gt;Graph Visualization Software&lt;/i&gt;) is a package of open source tools initiated by &lt;a href="http://en.wikipedia.org/wiki/AT%26T_Labs"&gt;AT&amp;amp;T Research Labs&lt;/a&gt; for &lt;a href="http://en.wikipedia.org/wiki/Graph_drawing"&gt;drawing&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Graph_theory"&gt;graphs&lt;/a&gt; specified in &lt;a href="http://en.wikipedia.org/wiki/DOT_language"&gt;DOT language&lt;/a&gt; scripts. It also provides libraries for software applications to use the tools. Graphviz is &lt;a href="http://en.wikipedia.org/wiki/Free_software"&gt;free software&lt;/a&gt; licensed under the &lt;a href="http://en.wikipedia.org/wiki/Common_Public_License"&gt;Common Public License&lt;/a&gt;.&lt;/p&gt; &lt;/fieldset&gt;   &lt;p&gt;&lt;strong&gt;效果&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;废话不多说，首先上效果图：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/HCOONa/WindowsLiveWriter/Graphviz_8D16/%E7%BB%93%E6%9E%9C_2.png" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="结果" border="0" alt="结果" src="http://images.cnblogs.com/cnblogs_com/HCOONa/WindowsLiveWriter/Graphviz_8D16/%E7%BB%93%E6%9E%9C_thumb.png" width="260" height="218" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;有继承，有扩展，有包含，是一个比较全面的用例图。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;代码&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Graphviz是使用Dot脚本描述图形的，我们来看看上面那幅用例图的代码：&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:45321045-c12f-4649-adf5-4686e820115d" class="wlWriterEditableSmartContent"&gt;digraph G {&lt;br/&gt;graph [rankdir=LR];&lt;br/&gt;&lt;br/&gt;subgraph cluster_Actor2 {&lt;br/&gt;a2;&lt;br/&gt;label = "Actor2";&lt;br/&gt;labelloc = b;&lt;br/&gt;color = white;&lt;br/&gt;}&lt;br/&gt;a2 [color=white, label="", shape=box, image="stick.png"];&lt;br/&gt;&lt;br/&gt;a2 -&amp;gt; Case2;&lt;br/&gt;Case2 -&amp;gt; { Case21 Case22 } [style=dashed, label="&amp;lt;&amp;lt;extends&amp;gt;&amp;gt;", dir=back];&lt;br/&gt;&lt;br/&gt;subgraph cluster_Actor1 {&lt;br/&gt;a1;&lt;br/&gt;label = "Actor1";&lt;br/&gt;labelloc = b;&lt;br/&gt;color = white;&lt;br/&gt;}&lt;br/&gt;a1 [color=white, label="", shape=box, shapefile="stick.png"];&lt;br/&gt;&lt;br/&gt;a1 -&amp;gt; Case1;&lt;br/&gt;&lt;br/&gt;Case1 -&amp;gt; Case11 [style=dashed, label="&amp;lt;&amp;lt;include&amp;gt;&amp;gt;"];&lt;br/&gt;Case1 -&amp;gt; { Case12 Case13 } [style=dashed, label="&amp;lt;&amp;lt;extends&amp;gt;&amp;gt;", dir=back];&lt;br/&gt;&lt;br/&gt;a1 -&amp;gt; a2[arrowtail = empty, dir=back];&lt;br/&gt;&lt;br/&gt;{ rank = same; a1; a2; }&lt;br/&gt;}&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;代码比较少，看起来也比较显然，但是我们还是一步一步分析一下。&lt;/p&gt;&lt;p&gt;首先diagraph G{}表示将绘制一个有向图；graph [rankdir=LR]表示图中元素的排列方式是按照从左向右排列的（默认从左到右，从上到下，即LD）。&lt;/p&gt;&lt;p&gt;由于Graphviz中没有内置Actor的图形，所以我们需要自己绘制一个Actor。这里我给提供一个：&lt;/p&gt;&lt;p&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="stick" border="0" alt="stick" src="http://images.cnblogs.com/cnblogs_com/HCOONa/WindowsLiveWriter/Graphviz_8D16/stick_3.png" width="62" height="110" /&gt; &lt;/p&gt;&lt;p&gt;Graphviz中对于图片上的标记默认会显示在图片正中，为了让Actor的Label显示在小人的下方，我们不得不做一个trick：&lt;/p&gt;&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:14bd585f-7c61-4fcd-9585-c5cc08ee6e6c" class="wlWriterEditableSmartContent"&gt;subgraph cluster_Actor2 {&lt;br/&gt;a2;&lt;br/&gt;label = "Actor2";&lt;br/&gt;labelloc = b;&lt;br/&gt;color = white;&lt;br/&gt;}&lt;br/&gt;a2 [color=white, label="", shape=box, image="stick.png"];&lt;/div&gt;&lt;p&gt;除了这一点比较讨厌以外，其他的地方就非常优雅了。比如说，a2如果有两个用例：Case1和Case2的话，那么使用如下语句即可描述：&lt;/p&gt;&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:04df5081-5f3c-4fbd-901c-019f21ca16ba" class="wlWriterEditableSmartContent"&gt;a2 -&amp;gt; { Case1, Case2 };&lt;/div&gt;&lt;p&gt;注释的形式和C++语言是相同的。如果不想要箭头的话，可以使用如下语句：&lt;/p&gt;&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:de423182-9ba7-4729-b60c-5dc842ffd099" class="wlWriterEditableSmartContent"&gt;a2 -- { Case1, Case2 };&lt;/div&gt;&lt;p&gt;也可以连续的进行描述：&lt;/p&gt;&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:ac909d5b-3ce9-4c5e-bbea-a0d40202ec34" class="wlWriterEditableSmartContent"&gt;a2 -- Case3 -&amp;gt; { Case31, Case32 };&lt;/div&gt;&lt;p&gt;总之就是你怎么想的，就可以怎么画：）根本不需要你考虑他们都画到了什么位置，Graphviz会自动为你调整的。&lt;/p&gt;&lt;p&gt;唯一需要注意的是，A –&amp;gt; B这种情况会对A和B产生一种关系，这种关系决定了A和B在布局时的位置，如果A是B的上一级，而又需要产生一个由B指向A的箭头，则需要使用下面这样的语句：&lt;/p&gt;&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:6780fc7e-f3bc-488c-a203-177eb938f3e7" class="wlWriterEditableSmartContent"&gt;A -&amp;gt; B [dir=back];&lt;/div&gt;&lt;p&gt;而最后一句&lt;/p&gt;&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:1c584765-8e23-49fe-9b3c-4a1ff229226e" class="wlWriterEditableSmartContent"&gt;{ rank = same; a1; a2; }&lt;/div&gt;&lt;p&gt;只是为了将Actor对齐。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;优势&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;使用Graphviz绘制关系图，只需要描述图中个元素之间的关系即可，而不需要考虑其他问题，可谓“所想即所得”，与使用Visio进行绘图相比较要优雅、快速的多。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;题外话&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;使用Graphviz绘制类图和时序图的话，可以使用&lt;a href="http://www.umlgraph.org" target="_blank"&gt;UMLGraph&lt;/a&gt;。如果用例图不仅仅是团队交流用，还用于Case工具的其他应用，最好还是使用Case套件进行绘图，比如说Rose。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;参考资料&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://martin.elwin.com/blog/2008/05/uml-use-case-diagrams-graphviz/"&gt;http://martin.elwin.com/blog/2008/05/uml-use-case-diagrams-graphviz/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://wiki.woodpecker.org.cn/moin/GraphViz"&gt;http://wiki.woodpecker.org.cn/moin/GraphViz&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://wiki.woodpecker.org.cn/moin/GraphVizForMoin"&gt;http://wiki.woodpecker.org.cn/moin/GraphVizForMoin&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/HCOONa/aggbug/1789777.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/HCOONa/archive/2010/08/01/1789777.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
