<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_Creason's Tech Blog</title><subtitle type="text">知识改变命运，技术创造未来，创新驱动人生。相信自己的力量……</subtitle><id>http://feed.cnblogs.com/blog/u/48654/rss</id><updated>2012-03-24T14:21:42Z</updated><author><name>Creason New</name><uri>http://www.cnblogs.com/niuchenglei/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/niuchenglei/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/48654/rss"/><entry><id>http://www.cnblogs.com/niuchenglei/archive/2010/09/20/1831446.html</id><title type="text">有关独立集的算法</title><summary type="text">关于独立集的问题有很多，比如地图填色问题、区域控制问题等。好多实际问题都可以抽象成独立集的问题，然后解决，比如对地图上的国家填充颜色，相邻的国家不能使用同一种颜色，这时就可以使用独立集求解。在上篇文章中《带权请求策略的几种算法》中，一种解法就使用了独立集的方法，下面我也会把具体的解法写出来。 问题描述 图g表示为，v为g的顶点集，e为g的边集，设顶点a属于独立集s，那么s中所有属于图g的顶点都没有...</summary><published>2010-09-19T23:46:00Z</published><updated>2010-09-19T23:46:00Z</updated><author><name>Creason New</name><uri>http://www.cnblogs.com/niuchenglei/</uri></author><link rel="alternate" href="http://www.cnblogs.com/niuchenglei/archive/2010/09/20/1831446.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/niuchenglei/archive/2010/09/20/1831446.html"/><content type="html">&lt;div class="link"&gt;   &lt;p class="nofont"&gt;关于独立集的问题有很多，比如地图填色问题、区域控制问题等。好多实际问题都可以抽象成独立集的问题，然后解决，比如对地图上的国家填充颜色，相邻的国家不能使用同一种颜色，这时就可以使用独立集求解。在上篇文章中&lt;a href="http://www.cnblogs.com/niuchenglei/archive/2010/08/28/1810589.html" target="_blank"&gt;《带权请求策略的几种算法》&lt;/a&gt;中，一种解法就使用了独立集的方法，下面我也会把具体的解法写出来。&lt;/p&gt;    &lt;p class="tifont"&gt;问题描述&lt;/p&gt;    &lt;p class="nofont" align="left"&gt;图g表示为&lt;v  ,e&gt;，v为g的顶点集，e为g的边集，设顶点a属于独立集s，那么s中所有属于图g的顶点都没有边直接相连。&lt;/p&gt;    &lt;p class="figure"&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/niuchenglei/WindowsLiveWriter/1c7b2be13e0a_6BA5/figure9-1-1_thumb.jpg" width="600" height="300" /&gt;       &lt;br /&gt;figure 1.1 a independent set whose node colored gray in the graph &lt;/p&gt;    &lt;p class="nofont"&gt;我们称上图中灰色节点为图的一个独立集。一般独立集的问题有求解图的独立集，求解图的最大独立集问题。&lt;/p&gt;    &lt;p class="tifont"&gt;几种不同的独立集&lt;/p&gt;    &lt;p class="nofont"&gt;一个图可以有多个独立集，每一个独立集都有一些特性，对他们归纳总结，我大致分一下几个类别：最大独立集、最小独立集、最多独立集、最少独立集、关联顶点独立集。&lt;/p&gt;    &lt;ul&gt;     &lt;li&gt;最大独立集，这种独立集最为常见，就是图g的独立集中包含顶点最多的那一个独立集。 &lt;/li&gt;      &lt;li&gt;最小独立集，顾名思意，相对于最大独立集来说，就是包含顶点最少的独立集，所以它没有研究意义，它包含的顶点数恒等于1 &lt;/li&gt;      &lt;li&gt;最少独立集，设s为包含图g独立集的集合，也就是说s的元素都是图g的独立集，且s中元素包含的顶点=图g的顶点集v，当s的容量最小时，我们称s为g的最少独立集。在scheduling all intervals（多资源请求安排策略，多个请求使用同一资源，但时间有交叉，求提供最少的资源满足这些请求。）问题上，可以使用最少独立集的理论来解决，而不是贪心算法。 &lt;/li&gt;      &lt;li&gt;最多独立集，相对于上面的最少独立集，它没有研究意义，最多独立集恒等于{{a},{b},……} &lt;/li&gt;      &lt;li&gt;关联顶点最大独立集，即包含顶点a的关于图g的独立集，有时候为了获得包含某顶点的独立集，我们不得不求出图全部的独立集，这很浪费资源，因此更好的策略是直接求关于某点的独立集。 &lt;/li&gt;   &lt;/ul&gt;    &lt;p class="tifont"&gt;求解几种不同独立集的算法&lt;/p&gt;    &lt;p class="sufont"&gt;1.最少独立集求解算法&lt;/p&gt;    &lt;p class="nofont"&gt;从上一节我们知道了最少独立集的概念，怎么求解图g的最少独立集呢？本方法我叫做验证法，下面是伪代码：&lt;/p&gt;    &lt;div class="mycode"&gt;&lt;br/&gt;//初始化最少集S，当前独立集s1&lt;br/&gt;S={};s1={V[0]};&lt;br/&gt;S.Append(s1);&lt;br/&gt;//遍历顶点集V&lt;br/&gt;for(i=1;i&amp;lt;V.length;i++){&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//如果当前顶点与前面所有的独立集有边&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(V[i]与S中的顶点有边){&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//初始化一个新的独立集&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ns={};&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ns.Append(V[i]);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;S.Append(ns);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else{&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//遍历S中的所有独立集&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(i=0;i&amp;lt;S.length;i++)&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(S[i]中所有的顶点与V[i]都没有边)&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;S[i].Append(V[i]);break;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;}&lt;br/&gt;    &lt;/div&gt;  &lt;p class="nofont"&gt;其实本算法很简单，先把第一个顶点a加入到第一个独立集s1中，然后依次遍历每一个顶点，如果当前顶点与集合s1中的顶点有边，就新建一个独立集s2，并把当前顶点加入s2中，照此规则，最终生成的几个独立集将是最少独立集的解。     &lt;br /&gt;例如，对于figure 1.1算法的执行情况是：&lt;/p&gt;  &lt;ul&gt;    &lt;li&gt;第一步：&amp;#160;&amp;#160;&amp;#160; s1={a}, s={s1} &lt;/li&gt;    &lt;li&gt;遍历b顶点：&amp;#160;&amp;#160;&amp;#160; s1={a}, s2={b}, s={s1,s2} &lt;/li&gt;    &lt;li&gt;遍历c顶点：&amp;#160;&amp;#160;&amp;#160; s1={a}, s2={b,c}, s={s1,s2} &lt;/li&gt;    &lt;li&gt;遍历d顶点：&amp;#160;&amp;#160;&amp;#160; s1={a,d}, s2={b,c}, s={s1,s2} &lt;/li&gt;    &lt;li&gt;遍历e顶点：&amp;#160;&amp;#160;&amp;#160; s1={a,d}, s2={b,c}, s3={e} s={s1,s2,s3} &lt;/li&gt;    &lt;li&gt;遍历f顶点：&amp;#160;&amp;#160;&amp;#160; s1={a,d,f}, s2={b,c}, s3={e} s={s1,s2,s3} &lt;/li&gt;    &lt;li&gt;遍历g顶点：&amp;#160;&amp;#160;&amp;#160; s1={a,d,f}, s2={b,c,g}, s3={e} s={s1,s2,s3} &lt;/li&gt;    &lt;li&gt;遍历h顶点：&amp;#160;&amp;#160;&amp;#160; s1={a,d,f}, s2={b,c,g}, s3={e}, s4={h} s={s1,s2,s3,s4} &lt;/li&gt;    &lt;li&gt;遍历i顶点：&amp;#160;&amp;#160;&amp;#160; s1={a,d,f}, s2={b,c,g,i}, s3={e}, s4={h} s={s1,s2,s3,s4} &lt;/li&gt;  &lt;/ul&gt;  &lt;p class="nofont"&gt;说到这里，我想大家都明白本算法是怎么回事了，非常简单不是吗？但是，这里有一个问题，就是通过这种算法形成的解中，会有一些独立集中顶点数量特别多，有些独立集的顶点数量又特别少，我称这种现象为“独立集失衡”，那么怎么生成一个较为“平衡”但又是最少的独立集呢？只需要做小小改进即可。&lt;/p&gt;  &lt;p class="nofont"&gt;重新回到上面的算法，当一个顶点与当前解集s中没有边时，应该把该顶点加入s中的哪一个独立集中呢？s1,s2还是s3，这就是造就“独立集失衡”的罪魁祸首，上面的算法是始终从第一个独立集开始，如果当前顶点与该独立集没有边，就加入到该集中，也就是说，我们每一次都“关照”排名考前的独立集，好了，说到这里，解决“独立集失衡”问题的方法迎刃而解，我们增加一个计数器，记录最后添加顶点的独立集的索引，下一次向独立集添加顶点时从它的下家开始就ok了。下面是伪代码：&lt;/p&gt;  &lt;div class="mycode"&gt;&lt;br/&gt;//初始化最少集S，当前独立集s1&lt;br/&gt;S={};s1={V[0]};&lt;br/&gt;S.Append(s1);&lt;br/&gt;//失衡计数器&lt;br/&gt;int count=0;&lt;br/&gt;//遍历顶点集V&lt;br/&gt;for(i=1;i&amp;lt;V.length;i++){&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//如果当前顶点与前面所有的独立集有边&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(V[i]与S中的顶点有边){&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//初始化一个新的独立集&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ns={};&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ns.Append(V[i]);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;S.Append(ns);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else{&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//遍历S中的所有独立集&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(i=0;i&amp;lt;S.length;i++){&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int index;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if((count+i)&amp;gt;S.length)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;index=i-count-1;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;index=i+count;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(S[index]中所有的顶点与V[i]都没有边){&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;S[index].Append(V[i]);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;count++;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;}&lt;br/&gt;    &lt;/div&gt;  &lt;p class="nofont"&gt;以上算法的解为：s1={a,d,f}, s2={b,c,g}, s3={e,i}, s4={h}&lt;/p&gt;  &lt;p class="sufont"&gt;2.关联顶点最大独立集求解算法&lt;/p&gt;  &lt;p class="nofont"&gt;怎么求解包含某个顶点的最大独立集呢？我们当然可以用枚举法产生，因为我们是程序员，所以总会有更好的方法，就像万能的上帝，什么时候都不乏好的想法。&lt;/p&gt;  &lt;p class="nofont"&gt;我们先思考一个最大的独立集所具有的特征，我们发现几乎所有的独立集中包含的顶点的“度”都不会太大。度，就是顶点的边数，对于有向图还有入度和出度的概念。假设，某个顶点的度很大，以至于它跟每一个顶点都有一条边，那么包含这个顶点的独立集绝对不会是最大独立集。基于这个想法，我们从顶点的度入手，运用贪心策略，我们每一步都尽量选择度数小的顶点作为最大独立集中的顶点。对于figure 1.1中的图，它们的度为：&lt;/p&gt;  &lt;p class="figure"&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/niuchenglei/WindowsLiveWriter/1c7b2be13e0a_6BA5/figure9-1-2%5B6%5D_thumb.jpg" width="600" height="300" /&gt;     &lt;br /&gt;figure 3.1 degree of the graph &lt;/p&gt;  &lt;p class="nofont"&gt;按照度数小优先的原则，我们可以生成一个包含某顶点的最大独立集。下面是伪代码：&lt;/p&gt;  &lt;div class="mycode"&gt;&lt;br/&gt;//初始化独立集S和临时集&lt;br/&gt;S={A};cur={};exploed={A}+f(A)&lt;br/&gt;while(exploed!=V){&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//遍历S中“邻居”的“邻居”，即A外2层的节点，并加入cur集合中&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cur={x|x∈f(f(S))}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//f(x)函数表示与x集合中顶点有边的所有顶点&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exploed.Append(cur);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//按照顶点的度对cur升序排序&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cur.Sort("ASC");&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//遍历cur中的顶点直到cur为空&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(i=0;cur!=null;i++){&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;S.Append(cur[i]);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//删除cur中与cur[i]有边的顶点&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;S.Delete(Disjoin(cur[i]));&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;}&lt;br/&gt;    &lt;/div&gt;  &lt;p class="nofont"&gt;比如，我们求解包含a的最大独立集，下面是代码的执行过程：&lt;/p&gt;  &lt;ul&gt;    &lt;li&gt;第一步：&amp;#160;&amp;#160;&amp;#160; cur={},exploed={a} s={a} &lt;/li&gt;    &lt;li&gt;第一次循环：&amp;#160;&amp;#160;&amp;#160; cur={f,g,h,d},exploed={a,f,g,h,d} s={a,f,h} &lt;/li&gt;    &lt;li&gt;第二次循环：&amp;#160;&amp;#160;&amp;#160; cur={i},exploed={a,f,g,h,d,i} s={a,f,h,i} &lt;/li&gt;    &lt;li&gt;终止：&amp;#160;&amp;#160;&amp;#160; exploed+f(a)=v&amp;#160;&amp;#160;&amp;#160; cur={},exploed={a,f,g,h,d,i} s={a,f,h,i} &lt;/li&gt;  &lt;/ul&gt;  &lt;p class="nofont"&gt;在算法的执行过程中，临时集合cur是在不断变化的，本算法的执行效率与图的结构有关。我称这种算法为最小度优先加点法。对于大的图，它可能不会生成一个包含某顶点的最大独立集，但是可以近似的最大了，本算法的一些特性还有待研究，希望大家多不吝言辞。&lt;/p&gt;  &lt;p class="tifont"&gt;最大独立集求解算法&lt;/p&gt;  &lt;p class="nofont"&gt;在独立集的诸多问题中，最大独立集是最重要的也是最常用的一种独立集情形。怎么生成一个图的最大独立集呢？我这有三种算法，一种是网络上的算法，另外两种是我的见解。&lt;/p&gt;  &lt;p class="sufont"&gt;1.最小覆盖集算法&lt;/p&gt;  &lt;p class="nofont"&gt;图g(v,e)的覆盖集d是顶点集的一个子集,并满足:任意 &amp;lt;vi,vj&amp;gt;属于e,vi属于d或vj属于d&amp;#160;&amp;#160; &lt;br /&gt;    &lt;br /&gt;定义 *，+ 满足交换率，结合率，&amp;#160; &lt;br /&gt;且 *对+分配 (a+b)*c = a*c + b*c&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;吸收率：&amp;#160; &lt;br /&gt;a+ab = a&amp;#160; &lt;br /&gt;a*a = a&amp;#160; &lt;br /&gt;a+a = a&amp;#160; &lt;br /&gt;    &lt;br /&gt;这样，求极小覆盖集：&amp;#160; &lt;br /&gt;    &lt;br /&gt;m(连乘)(&amp;#160; (v[i]&amp;#160; +&amp;#160; m(所有与v[i]相邻的点)&amp;#160;&amp;#160; )&amp;#160; &lt;br /&gt;i=0 to n&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;    &lt;br /&gt;结果化简后的每个因子项即对应一个极小覆盖集。&amp;#160; &lt;br /&gt;    &lt;br /&gt;for example:&amp;#160; &lt;br /&gt;a---b---c&amp;#160; &lt;br /&gt;\ / \ /&amp;#160; &lt;br /&gt;&amp;#160; d&amp;#160;&amp;#160; e&amp;#160; &lt;br /&gt;    &lt;br /&gt;(a+bd)(b+acde)(c+be)(d+ab)(e+bc)&amp;#160; &lt;br /&gt;= acde+abe+bcd+abc+bde&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;    &lt;br /&gt;acde,abe,bcd,abc,bde 既是g的各个极小覆盖集。&amp;#160; &lt;br /&gt;    &lt;br /&gt;因为极小覆盖集和极大独立集互补，用abcde 减去各个极小覆盖集，&amp;#160; &lt;br /&gt;既得到极大独立集：&amp;#160; &lt;br /&gt;b dc ae de ac&amp;#160;&amp;#160; &lt;br /&gt;    &lt;br /&gt;其中dc ae de ac是最大独立集。&amp;#160; &lt;/p&gt;  &lt;p class="sufont"&gt;2.动态规划法&lt;/p&gt;  &lt;p class="nofont"&gt;动态规划算法的普适性很强，以至于什么问题我们都可以进行动态规划一下，但是对于某些问题，动态规划的效果却欠佳。     &lt;br /&gt;设p(x)为包含x的最大独立集，l(x)为x的相邻顶点。那么有：&lt;/p&gt;  &lt;p class="define"&gt;p(x)=x+max(p(y))&amp;#160;&amp;#160;&amp;#160; y∈{v-x-l(x)}&lt;/p&gt;  &lt;p class="nofont"&gt;有了上面的公式，算法便一目了然了。同样，这种方法还适用于关联顶点的独立集问题。它的效率实在太低了，所以大家就不要用了。&lt;/p&gt;  &lt;p class="sufont"&gt;3.最大度优先减点法&lt;/p&gt;  &lt;p class="nofont"&gt;在上面的关联顶点独立集的问题中我提到了一种算法，叫最小度优先加点法，原理是一样的，对于求最大独立集的问题，我们首先找到度数最大的顶点，然后删除它，直到生成一个独立集，那么得到的就是最大独立集了。对于figure 1.1中的示例，它的过程为：&lt;/p&gt;  &lt;ul&gt;    &lt;li&gt;第一步：删除e       &lt;p class="figure"&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/niuchenglei/WindowsLiveWriter/1c7b2be13e0a_6BA5/figure9-1-3%5B15%5D_thumb.jpg" width="600" height="300" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;/li&gt;    &lt;li&gt;第二步：删除d       &lt;p class="figure"&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/niuchenglei/WindowsLiveWriter/1c7b2be13e0a_6BA5/figure9-1-4%5B6%5D_thumb.jpg" width="600" height="300" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;/li&gt;    &lt;li&gt;第三步：最后剩下了“环”，删掉a,f,h       &lt;p class="figure"&gt;&amp;#160;&lt;a href="http://images.cnblogs.com/cnblogs_com/niuchenglei/WindowsLiveWriter/1c7b2be13e0a_6BA5/figure9-1-5_2.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="figure9-1-5" border="0" alt="figure9-1-5" src="http://images.cnblogs.com/cnblogs_com/niuchenglei/WindowsLiveWriter/1c7b2be13e0a_6BA5/figure9-1-5_thumb.jpg" width="571" height="274" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;/li&gt;  &lt;/ul&gt;  &lt;p class="nofont"&gt;在算法执行的最后，会剩下“环”或是“链”状的图，这时就有可能生成多个最大独立集了。&lt;/p&gt;  &lt;p class="tifont"&gt;独立集法求解带权请求策略&lt;/p&gt;  &lt;p class="nofont"&gt;在上一篇文章中，我提到了使用独立集的方案，在这里就稍作阐述。问题如下图：&lt;/p&gt;  &lt;p class="figure"&gt;&lt;img src="http://pic002.cnblogs.com/img/niuchenglei/201008/2010082800060391.jpg" width="700" height="200" /&gt;     &lt;br /&gt;figure 4.1 an instance of weighted interval scheduling with longest path &lt;/p&gt;  &lt;p class="nofont"&gt;首先，我们用请求的权值作为图的点，如果请求a,b冲突，就做边ab，于是得到图:&lt;/p&gt;  &lt;p class="figure"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="figure9-1-6[4]" border="0" alt="figure9-1-6[4]" src="http://images.cnblogs.com/cnblogs_com/niuchenglei/WindowsLiveWriter/1c7b2be13e0a_6BA5/figure9-1-6%5B4%5D_thumb_1.jpg" width="614" height="277" /&gt;     &lt;br /&gt;figure 4.2 general a graph from the interval &lt;/p&gt;  &lt;p class="nofont"&gt;得到了图，下一步就是应用我们的“最大度优先减点法”了，首先删除点e，然后是b，最后得到一个偶数链，删除链中的g以得到最大的权数。最终得到a,c,d,f请求，对应图中的：&lt;/p&gt;  &lt;p class="figure"&gt;&amp;#160;&lt;a href="http://images.cnblogs.com/cnblogs_com/niuchenglei/WindowsLiveWriter/1c7b2be13e0a_6BA5/figure9-1-7_2.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="figure9-1-7" border="0" alt="figure9-1-7" src="http://images.cnblogs.com/cnblogs_com/niuchenglei/WindowsLiveWriter/1c7b2be13e0a_6BA5/figure9-1-7_thumb.jpg" width="525" height="162" /&gt;&lt;/a&gt; figure 4.3 result we get from idependent set &lt;/p&gt;  &lt;p class="nofont"&gt;实际上，独立集法求解带权请求策略所使用的独立集策略为：最大权重独立集算法，而不是最大独立集算法，所以本处产生的结果不是带权请求的最优结果。关于最大权重独立集算法以后可能会涉及到。&lt;/p&gt;  &lt;p class="tifont"&gt;总结&lt;/p&gt;  &lt;p class="nofont"&gt;独立集的应用非常广，同时它也非常高效，有时候并不是所有的问题都适合用动态规划等方法，恰当的运用图的理论可以大大提高系统的效率。希望大家检验上面的算法，不吝言辞多提意见。&lt;/p&gt;  &lt;p class="warning"&gt;作者：creason new(&lt;a href="http://www.cnblogs.com/niuchenglei" target="_blank"&gt;creason's Blog&lt;/a&gt;)     &lt;br /&gt;出处：&lt;a href="http://www.cnblogs.com/niuchenglei " target="_blank"&gt; http://www.cnblogs.com/niuchenglei &lt;/a&gt;    &lt;br /&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。 &lt;/p&gt;&lt;/div&gt;&lt;script language="javascript" type="text/javascript" src="http://js.users.51.la/2866177.js"&gt;&lt;/script&gt; &lt;noscript&gt;&lt;/noscript&gt;&lt;img src="http://www.cnblogs.com/niuchenglei/aggbug/1831446.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/niuchenglei/archive/2010/09/20/1831446.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/niuchenglei/archive/2010/08/28/1810589.html</id><title type="text">带权请求策略的几种算法</title><summary type="text">在看《算法设计》的贪心算法时，有一个问题:Weight Interval Scheduling，也就是常常提到的带权请求策略问题，这个算法经常用到，比如CPU的进程调度，资源调度等。书中给出的方案是使用动态规划算法解出的，后来我发现也可以从图论的角度解决，就整理了一下思路，想出了几个解决问题的其它方案，在这里跟大家一同分享一下，探讨还有没有更多解法。问题描述在一定时间段内，有n个请求需要占用同一资...</summary><published>2010-08-27T16:08:00Z</published><updated>2010-08-27T16:08:00Z</updated><author><name>Creason New</name><uri>http://www.cnblogs.com/niuchenglei/</uri></author><link rel="alternate" href="http://www.cnblogs.com/niuchenglei/archive/2010/08/28/1810589.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/niuchenglei/archive/2010/08/28/1810589.html"/><content type="html">&lt;div class="link"&gt;&lt;p class="nofont"&gt;在看《算法设计》的贪心算法时，有一个问题:Weight Interval Scheduling，也就是常常提到的带权请求策略问题，这个算法经常用到，比如CPU的进程调度，资源调度等。书中给出的方案是使用动态规划算法解出的，后来我发现也可以从图论的角度解决，就整理了一下思路，想出了几个解决问题的其它方案，在这里跟大家一同分享一下，探讨还有没有更多解法。&lt;/p&gt;&lt;p class="tifont"&gt;问题描述&lt;/p&gt;&lt;p class="nofont" align="left"&gt;在一定时间段内，有n个请求需要占用同一资源，它们的起始和结束时间各不相同，每一个请求有一个权值，指示完成请求所付的报酬。那么，怎么才能得到最大的报酬。&lt;/p&gt;&lt;p class="figure"&gt;    &lt;img src="http://pic002.cnblogs.com/img/niuchenglei/201008/2010082800012987.jpg" height="130" width="440" /&gt;&lt;br /&gt;    Figure 1.1 A simple instance of weighted interval scheduling    &lt;/p&gt;&lt;p class="tifont"&gt;动态规划法&lt;/p&gt;&lt;p class="nofont"&gt;每一个请求i，都有起始和结束时间si,fi，共有n个请求，假设S是最终的解，那么S&amp;isin;{1..n}，解为&amp;sum;(i&amp;isin;S)vi。这里我们还要定义一个变量，p(i):&lt;/p&gt;&lt;p class="define"&gt;p(i):按照结束时间对n个请求正序排序，p(i)代表请求i前的结束时间最晚而且不相冲突的请求的索引，即i前最近的不相冲突的请求的索引，如果没有则为0。&lt;/p&gt;&lt;p class="figure"&gt;    &lt;img src="http://pic002.cnblogs.com/img/niuchenglei/201008/2010082800031034.jpg" height="270" width="600" /&gt;&lt;br /&gt;    Figure 2.1 An instance of weighted interval scheduling with the functions p(i) defined for each interval i.&lt;/p&gt;&lt;p class="nofont"&gt;设Oi为包含请求i的最优解，OPT(i)为Oi的总权值，那么OPT(0)=0，所以我们要求的便是On中的n，设j=n，当j&amp;isin;Oj时，那么OPT(j)=vj+OPT(p(j))，如果!j&amp;isin;Oj，那么OPT(j)=OPT(j-1)，于是：&lt;/p&gt;&lt;p class="define"&gt;OPT(j) = max( vj+OPT(p(j)) , OPT(j-1) ).&lt;/p&gt;&lt;p class="nofont"&gt;如果j属于最优解，那么当且仅当：vj+OPT(p(j)) &amp;gt;= OPT(j-1)&lt;/p&gt;&lt;p class="nofont"&gt;则整个过程为：&lt;/p&gt;&lt;div class="mycode"&gt;Compute-Opt(j)&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If j=0 then&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Return 0&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Else&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Return max(vj+Compute-Opt(p(j)), Compute-Opt(j-1))&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Endif&lt;br/&gt;&lt;/div&gt;&lt;p class="nofont"&gt;在程序运行时，我们发现很多时候我们重新计算了很多值，如果问题的规模非常大，那么这将是笔不小的开销：&lt;/p&gt;&lt;p class="figure"&gt;    &lt;img src="http://pic002.cnblogs.com/img/niuchenglei/201008/2010082800050083.jpg" height="500" width="670" /&gt;&lt;br /&gt;    Figure 2.2 The tree of subproblems called by Compute-Opt    &lt;/p&gt;&lt;p class="nofont"&gt;所以，要一个数组保存Opt(j)的值，改进后的算法为：&lt;/p&gt;&lt;div class="mycode"&gt;M-Compute-Opt(j)&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If j=0 then&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Return 0&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Else if M[j] is not empty then&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Return M[j]&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Else&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Define M[j] = max(vj+M-Compute-Opt(p(j)), M-Compute-Opt(j-1))&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Return M[j]&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Endif&lt;br/&gt;&lt;/div&gt;&lt;p class="nofont"&gt;最终算法的时间复杂度为O(n)，已经相当出色了，这就是动态规划的实力。&lt;/p&gt;&lt;p class="tifont"&gt;最大连通图法&lt;/p&gt;&lt;p class="nofont"&gt;我将通过一个实例来阐述这种方法，如下面图中的情况：&lt;/p&gt;&lt;p class="figure"&gt;    &lt;img src="http://pic002.cnblogs.com/img/niuchenglei/201008/2010082800060391.jpg" height="200" width="700" /&gt;&lt;br /&gt;    Figure 3.1 An instance of weighted interval scheduling with longest path    &lt;/p&gt;&lt;p class="nofont"&gt;首先，我把所有请求的起始终止时间投影到时间轴上，并对它们编号。&lt;br /&gt;    然后，绘制出图，其中点为时间点，边为时间点间的请求，边的权值为该请求的权值，如图：&lt;/p&gt;&lt;p class="figure"&gt;    &lt;img src="http://pic002.cnblogs.com/img/niuchenglei/201008/2010082800065170.jpg" height="500" width="700" /&gt;&lt;br /&gt;    Figure 3.2 Process of get a graph from requests    &lt;/p&gt;&lt;p class="nofont"&gt;从请求中得到图我们需要做一些额外的工作，正如上图中所示，首先如果请求i位于时间点a,b间，就连接a,b，并把请求i的权值作为边ab的权值。完成这一步我们将得到一个包含多个子图的弱连通图。然后，加入一个起始点s和一个结束点f，s连接到所有子图的最先时间点，f连接到所有子图的最迟时间点，并给它们0权值。最后，也是最重要的一步，就是连接各个子图，这一步有一个原则：&lt;/p&gt;&lt;p class="define"&gt;找到子图中最先时间点a，连接a之前的最邻近的时间点，并赋权值0。找子图中最迟的时间点b，连接b之后的最邻近的时间点，并赋权值0。这样，我们就得到一个连通图。继而，使用图的理论求得s,f间的最长路径，继而求解成功。&lt;/p&gt;&lt;p class="tifont"&gt;最大独立集法&lt;/p&gt;&lt;p class="nofont"&gt;独立集就是图中互不连通的点的集合，最大独立集也就是图中点数最多的独立集，根据这一理论，我们可以使用最大独立集法求解。&lt;/p&gt;&lt;p class="nofont"&gt;首先，我们用请求的权值作为图的点，如果请求a,b冲突，就做边ab，于是得到图。然后，根据图的理论求出图的最大独立集。&lt;/p&gt;&lt;p class="tifont"&gt;总结&lt;/p&gt;&lt;p class="nofont"&gt;有关带权请求策略的算法可能还有很多，以上的两种为本人的个人解法，可能没有第一种效率高，但针对不同的问题，使用图论来解决会得到更好的结果，具体的性能分析也没有测试，希望有兴趣的可以试一下。如果，你有更好的算法不妨说出来，让我们一起研究一下。&lt;/p&gt;&lt;p class="warning"&gt;      作者：Creason New(&lt;a href="http://www.cnblogs.com/niuchenglei" target="_blank"&gt;Creason's Blog&lt;/a&gt;)&lt;br /&gt;         出处：&lt;a href="http://www.cnblogs.com/niuchenglei" target="_blank"&gt; http://www.cnblogs.com/niuchenglei &lt;/a&gt;&lt;br /&gt;         本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。  &lt;/p&gt;&lt;/div&gt;&lt;script language="javascript" type="text/javascript"&gt;&lt;/script&gt;&lt;p&gt;&lt;noscript&gt;&lt;a href="http://www.51.la/?2866177" target="_blank"&gt;&lt;img alt="&amp;#x6211;&amp;#x8981;&amp;#x5566;&amp;#x514D;&amp;#x8D39;&amp;#x7EDF;&amp;#x8BA1;" src="http://img.users.51.la/2866177.asp" style="border:none" /&gt;&lt;/a&gt;&lt;/noscript&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/niuchenglei/aggbug/1810589.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/niuchenglei/archive/2010/08/28/1810589.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/niuchenglei/archive/2010/08/23/1806754.html</id><title type="text">G-S匹配算法优化（2）</title><summary type="text">“约会稳定性”和“稳定方向”上一篇最后，我们大致明确了如何去优化G-S算法，其中提到了“约会稳定性”和“稳定方向”的概念，如果还不是太明白请看优化G-S匹配算法（1）之兵马未动粮草先行为了提高“约会稳定性”我们计算得出“稳定方向”，然后沿着“稳...</summary><published>2010-08-23T12:19:00Z</published><updated>2010-08-23T12:19:00Z</updated><author><name>Creason New</name><uri>http://www.cnblogs.com/niuchenglei/</uri></author><link rel="alternate" href="http://www.cnblogs.com/niuchenglei/archive/2010/08/23/1806754.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/niuchenglei/archive/2010/08/23/1806754.html"/><content type="html">&lt;div class="link"&gt;&lt;p class="tifont"&gt;&amp;ldquo;约会稳定性&amp;rdquo;和&amp;ldquo;稳定方向&amp;rdquo;&lt;/p&gt;&lt;p class="nofont"&gt;上一篇最后，我们大致明确了如何去优化G-S算法，其中提到了&amp;ldquo;约会稳定性&amp;rdquo;和&amp;ldquo;稳定方向&amp;rdquo;的概念，如果还不是太明白请看&lt;a href="#"&gt;优化G-S匹配算法（1）之兵马未动粮草先行&lt;/a&gt;为了提高&amp;ldquo;约会稳定性&amp;rdquo;我们计算得出&amp;ldquo;稳定方向&amp;rdquo;，然后沿着&amp;ldquo;稳定方向&amp;rdquo;去一一匹配，便会得出比较优化的结果。但是，&amp;ldquo;稳定方向&amp;rdquo;的计算也不是一个轻巧的过程，本篇主要介绍如何去计算&amp;ldquo;稳定方向&amp;rdquo;这个过程，同时也希望大家提出更好的方案。&lt;/p&gt;&lt;p class="tifont"&gt;共识率和平均排名&lt;/p&gt;&lt;p class="nofont"&gt;我们知道，&amp;ldquo;稳定方向&amp;rdquo;是一个men对所有women的一个平均排名，有点想一个班里所有的男生讨论得出的自己班里班花排行一样，在G-S问题中，&amp;ldquo;稳定方向&amp;rdquo;的得出是从每一个man的优先列表中计算得出的，同样的women对men也有这样一个平均排名。&lt;/p&gt;&lt;p class="notetag"&gt;优先列表，在G-S问题中指一个人对所有异性的排名。比如，男人m喜欢女人w1胜过w2，则在m的优先列表中w1的位置比w2更靠前。&lt;br /&gt;平均排名，指的是men对women达成的一种优先共识，即大体上所有的man都认为woman的排名应该是这样的。&lt;/p&gt;&lt;p class="nofont"&gt;我们知道&amp;ldquo;稳定方向&amp;rdquo;代表着大多数人的意见，也就是说&amp;ldquo;稳定方向&amp;rdquo;是大多数人形成的一个共识，既然有共识，那么必然的存在着意见的不同。当我们给出一个优先列表A，设A为标准的平均排名，只是假设其实不存在标准的平均排名。那么如果大多数人大体同意A，也就是说能达成共识，如果大多数人不同意A，也就是说不能达成共识。于是，对A质量的评价就取决与人们对它达成共识的程度，我们称之为共识率。共识率的大小决定了人们意见的统一与分散，在G-S问题中，men对women的共识率决定了men对women排名的相近和不同。&lt;/p&gt;&lt;p class="notetag"&gt;共识率的作用非常大，如果共识率较低，说明平均排名没有说服力，不能代表大部分人的意见，因此对算法提高的效率产生的积极影响也小，反之，对算法效率的提供帮助越大。如果共识率非常低以至于趋近于0，则优化后的算法跟传统的算法没有区别。&lt;/p&gt;&lt;p class="nofont"&gt;因此，我们应先计算出平均排名，再计算优先列表相对平均排名的共识率，以说明平均排名的结果是否可信，可信度为多少。&lt;/p&gt;&lt;p class="tifont"&gt;平均排名的计算&lt;/p&gt;&lt;p class="nofont"&gt;平均排名的计算是对一组优先列表的计算产生的，n个man对应n个优先列表，那么如何从这么多的优先列表中计算出平均排名呢？&lt;br /&gt;我采用了一种方法，叫做&lt;strong&gt;逆序数逐步求精法&lt;/strong&gt;。&lt;/p&gt;&lt;p class="notetag"&gt;逆序数，指一个数列相对于标准数列的逆序的总和。&lt;br /&gt;比如，2314的逆序数为2（相对于1234）。&lt;br /&gt;我们很容易知道，有n个数，那么该数列最大的逆序数Nmax=n(n-1)/2。&lt;/p&gt;&lt;p class="nofont"&gt;比如有man A、B、C、D。他们对woman的优先列表分别为：&lt;br /&gt;A:{a,b,c,d}&lt;br /&gt;B:{d,c,a,b}&lt;br /&gt;C:{c,d,b,a}&lt;br /&gt;D:{d,a,c,b}&lt;br /&gt;我们假设A的优先列表与平均排名相同，则A、B、C、D的优先列表对于平均排名的逆序数为0,5,5,4，逆序数越大，说明它们与平均排名差别越大，dcba与平均排名abcd的差别最大，dcba的逆序数为6，所以根据贪心原则，当每一个优先列表的逆序数最小时，总逆序数最小，也就说明各个优先列表间差别最小，即达成一个共识。&lt;/p&gt;&lt;p class="nofont"&gt;因此，设所有优先列表逆序数的和为R，优先列表i的逆序数为Vi，则R=&amp;sum;Vi(0&amp;lt;=i&amp;lt;=n)。&lt;strong&gt;当R达到最小时，当前假设的平均排名最接近标准的平均排名，我们取它作为平均排名来作为&amp;ldquo;稳定方向&amp;rdquo;&lt;/strong&gt;，并技术该&amp;ldquo;稳定方向&amp;rdquo;的共识率。&lt;/p&gt;&lt;p class="nofont"&gt;怎么个逐步求精呢？以上面的ABCD为例：&lt;/p&gt;&lt;p class="sufont"&gt;1.假设平均排名&lt;/p&gt;&lt;p class="nofont"&gt;我们首先假设A的优先列表为平均排名。则ABCD的优先列表相对于平均排名的逆序数为0,5,5,4。&lt;br /&gt;A:{a,b,c,d}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0&lt;br /&gt;B:{d,c,a,b}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;5&lt;br /&gt;C:{c,d,b,a}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;5&lt;br /&gt;D:{d,a,c,b}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4&lt;br /&gt;从BCD优先列表的逆序数上我们可以看出它们与平均排名相差甚远，因为最大的逆序数为6，它们已经非常接近最大逆序数了。但是，我们发现BCD优先列表的逆序数却很相似。&lt;/p&gt;&lt;p class="sufont"&gt;2.计算平均逆序数修正假设&lt;/p&gt;&lt;p class="nofont"&gt;为了更进一步逼近标准平均排名，我们找出最接近平均逆序数的那个优先列表，并假设它为平均排名。&lt;br /&gt;逆序数和R=0+5+5+4=14，平均逆序数r=14/4=3.5，D优先列表的逆序数最接近，因此设D的优先列表为平均排名，下面是以D优先列表为平均排名计算出的逆序数：&lt;br /&gt;A:{a,b,c,d}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4&lt;br /&gt;B:{d,c,a,b}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1&lt;br /&gt;C:{c,d,b,a}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3&lt;br /&gt;D:{d,a,c,b}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0&lt;br /&gt;R=8,r=2，比起上一步显然D比A的优先列表作为平均排名更合适。&lt;br /&gt;然后回到1，直到满足3退出得到平均排名。&lt;/p&gt;&lt;p class="sufont"&gt;3.终止逐步求精，得到平均排名&lt;/p&gt;&lt;p class="nofont"&gt;1和2给出了计算过程，但是缺少一个终止的条件，就是我们需要记录上一次平均排名的逆序数和R1和这一步的逆序数和R2，然后取R1和R2中值较小的一个作为平均排名，如果R1和R2相同，则有两种方法：一种是取优先列表逆序数方差小的一个，一种是取共识率更高的一个。共识率的计算在接下来会介绍。&lt;br /&gt;在2中，我们以D的优先列表作为平均排名计算的结果已经给出，然后再选B的优先列表作为平均排名，计算出R=8,r=2。那么到底B和D的优先列表那个更接近标准优先列表呢？按照方差小优先的方法，B的优先列表更接近标准优先列表，于是我们得出了&amp;ldquo;稳定方向&amp;rdquo;为B的优先列表，接着就是共识率的计算。&lt;/p&gt;&lt;p class="tifont"&gt;共识率的计算&lt;/p&gt;&lt;p class="nofont"&gt;我们设所有优先列表相对平均排名的共识率为Q，每一个优先列表相对于平均排名的共识率为q，则有：&lt;br /&gt;&lt;strong&gt;Q=&amp;sum;qi/n&lt;/strong&gt;&lt;br /&gt;以abcd为基准，则dcba的逆序数为6，abcd的逆序数为0，dcab的逆序数为5，因为逆序数表示的是位置先后的差异度，abcd全排列得到6种组合（ab/ac/ad/bc/bd/cd组合内无先后顺序），则在dcba种也可以找到这6种组合，那么如果abcd6种组合中的一个在dcba中的顺序不同时，逆序数加1（比如abcd中ab组合a在前b在后，而在dcba中ab组合a在后b在前），所以逆序数又可以看做是每一对组合的顺序差异。那么，对于q有：&lt;br /&gt;&lt;strong&gt;q=(Nmax-r)/Nmax&lt;/strong&gt;&lt;br /&gt;Nmax是我们前面提到的最大逆序数。Nmax=n(n-1)/2&lt;br /&gt;这样我们便求出了每个优先列表对于平均排名的共识率，继而得出所有优先列表对于平均排名的共识率。&lt;br /&gt;&lt;strong&gt;Q=(1-R/(Nmax*n))*100%&lt;/strong&gt;&lt;/p&gt;&lt;p class="nofont"&gt;在&amp;ldquo;平均排名的计算&amp;rdquo;一节中的第3步，有这么一种情况，就是我们计算出以B和D优先列表作为平均排名它们的逆序数和R都等于8，而共识率Q又与R有关，所以从共识率上我们看不出B和D那个的优先列表作为平均排名更好些，所以我们采用方差最小优先法。&lt;/p&gt;&lt;p class="tifont"&gt;&amp;ldquo;强&amp;rdquo;平均排名&lt;/p&gt;&lt;p class="nofont"&gt;通过上面的介绍，相信大家都了解了求&amp;ldquo;稳定方向&amp;rdquo;的整个过程，但是我们求出来的平均排名有一个问题，上面求出来的平均排名我称之为&amp;ldquo;弱&amp;rdquo;平均排名，为什么呢？&lt;br /&gt;细心的朋友发现不管ABCD的优先列表如何，我们求出的平均排名肯定是ABCD的优先列表中的一个，这显然不符合实际问题，如果man的数量庞大，有可能这里的&amp;ldquo;弱&amp;rdquo;平均排名==&amp;ldquo;强&amp;rdquo;平均排名，所以&amp;ldquo;强&amp;rdquo;平均排名更接近与标准的平均排名。怎么化解这个弊端呢？就是通过引入全排列，并计算它们相对于当前假设的平均排名的逆序数，比如ABCDEF的优先列表的逆序数为0,1,2,13,12,12则R=40,r=6.67显然，没有ABCDEF的优先列表中没有一个符合要求，则需要引入其它的假设的平均排名，进而求出&amp;ldquo;强&amp;rdquo;平均排名。&lt;/p&gt;&lt;p class="nofont"&gt;引入&amp;ldquo;强&amp;rdquo;平均排名后，因为在获取符合要求的假设平均排名时需要计算每一个全排列的逆序数并获取最接近平均逆序数的一个作为假设的新的平均排名，所以问题的求解规模会很大，而且对于小规模问题我们可以使用传统的G-S算法，对于大规模问题，如果使用&amp;ldquo;强&amp;rdquo;平均排名由于问题规模较大(man的人数n较大，则n个全排列的逆序数的计算和比较会很消耗资源)，求解&amp;ldquo;强&amp;rdquo;平均排名的过程会消耗非常大的资源，甚至远不如不优化，而且随着问题规模的增大，&amp;ldquo;弱&amp;rdquo;平均排名也趋近于&amp;ldquo;强&amp;rdquo;平均排名，所以，在理论上，存在这么一个误区，而在实际问题中，如果采用&amp;ldquo;强&amp;rdquo;平均排名就得不偿失了。这里就不再做详细分析，有兴趣的朋友可以研究一下。&lt;/p&gt;&lt;p class="tifont"&gt;形成&amp;ldquo;稳定方向&amp;rdquo;伪代码&lt;/p&gt;&lt;div class="mycode"&gt;int[] preO=第一个woman的优先列表&lt;br/&gt;int[] nowO=preO&lt;br/&gt;int[] preR=preO的逆序数数列&lt;br/&gt;int[] nowR=preR&lt;br/&gt;int preRN=preR的总和,nowRN=0&lt;br/&gt;while(true){&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;选择最接近平均逆序数r的优先列表B,并nowO=B&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nowR=nowO的逆序数数列&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nowRN=nowR逆序数和&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(nowRN&amp;gt;preRN)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else if(nowR==preR){&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(方差(nowR)&amp;lt;方差(preR)){&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;preO=nowO&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;preR=nowR&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;preRN=nowRN&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else{&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;preO=nowO&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;preR=nowR&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;preRN=nowRN&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;}&lt;br/&gt;preO作为平均排名,preR作为逆序数数列,preRN作为逆序数和&lt;br/&gt;Q=(1-preRN/(Nmax*n))*100%&lt;br/&gt;返回preO作为&amp;ldquo;稳定方向&amp;rdquo;，Q作为共识率&lt;br/&gt;&lt;/div&gt;&lt;p class="nofont"&gt;&lt;a href="http://www.cnblogs.com/niuchenglei/archive/2010/08/20/1804915.html"&gt;G-S匹配算法优化（1）&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.cnblogs.com/niuchenglei/archive/2010/08/23/1806754.html"&gt;G-S匹配算法优化（2）&lt;/a&gt;&lt;/p&gt;&lt;p class="warning"&gt;作者：Creason New(&lt;a target="_blank" href="http://www.cnblogs.com/niuchenglei"&gt;Creason's Blog&lt;/a&gt;)&lt;br /&gt; 出处：&lt;a target="_blank" href="http://www.cnblogs.com/niuchenglei"&gt; http://www.cnblogs.com/niuchenglei &lt;/a&gt;&lt;br /&gt; 本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/p&gt;&lt;/div&gt;&lt;script type="text/javascript" language="javascript"&gt;&lt;/script&gt;&lt;p&gt;&lt;noscript&gt;&lt;a href="http://www.51.la/?2866177" target="_blank"&gt;&lt;img alt="&amp;#x6211;&amp;#x8981;&amp;#x5566;&amp;#x514D;&amp;#x8D39;&amp;#x7EDF;&amp;#x8BA1;" src="http://img.users.51.la/2866177.asp" style="border:none" /&gt;&lt;/a&gt;&lt;/noscript&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/niuchenglei/aggbug/1806754.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/niuchenglei/archive/2010/08/23/1806754.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/niuchenglei/archive/2010/08/20/1804915.html</id><title type="text">G-S匹配算法优化（1）</title><summary type="text">重温稳定匹配算法（G-S算法）稳定匹配问题是一个非常典型的算法问题，它是由Gale和Shapley共同提出的。问题是这样描述的：1.问题发生的背景在大学期间，很多学生会选择去找实习公司实习，那么就会有很多同学对很多公司发出实习申请。申请过程的关键是两类不同的参与者：公司（雇主）和学生（申请人）之间的相互影响。每个申请人对公司有一个优先排序，一旦申请人来到公司，每个公司对它的申请人也构成一个优先排序...</summary><published>2010-08-20T12:17:00Z</published><updated>2010-08-20T12:17:00Z</updated><author><name>Creason New</name><uri>http://www.cnblogs.com/niuchenglei/</uri></author><link rel="alternate" href="http://www.cnblogs.com/niuchenglei/archive/2010/08/20/1804915.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/niuchenglei/archive/2010/08/20/1804915.html"/><content type="html">&lt;div class="link"&gt;&lt;p class="tifont"&gt;重温稳定匹配算法（G-S算法）&lt;/p&gt;&lt;p class="nofont"&gt;稳定匹配问题是一个非常典型的算法问题，它是由Gale和Shapley共同提出的。问题是这样描述的：&lt;/p&gt;&lt;p class="sufont"&gt;1.问题发生的背景&lt;/p&gt;&lt;p class="nofont"&gt;在大学期间，很多学生会选择去找实习公司实习，那么就会有很多同学对很多公司发出实习申请。申请过程的关键是两类不同的参与者：公司（雇主）和学生（申请人）之间的相互影响。每个申请人对公司有一个优先排序，一旦申请人来到公司，每个公司对它的申请人也构成一个优先排序。基于这些优先排序，公司对他们的某些申请人发出录用通知书，而申请人则选择某个通知书来接受，于是人们开始进入实习工作。&lt;/p&gt;&lt;p class="nofont"&gt;好，到这里问题出现了。比如，假设你的朋友Mark接受到Microsoft的录用通知书，另一个公司Yahoo行动晚了一些，几天后它也给Mark发出了录用通知书。而Mark更愿意去Yahoo而不是Microsoft，于是这个新的发展也可能使他取消Microsoft的录用通知。由于突然少了一个实习生，Microsoft就会重新录用另一个学生。似乎问题越来越严重，新的问题又来了。Mark有一个朋友叫Bill，他本来已经收到了Microsoft的录用通知书，而恰恰Yahoo是知道这个消息的。经过与Mark的交流，Bill发现Microsoft公司并不是自己希望的那样，而Yahoo却是自己的所愿。于是Bill给Microsoft打电话取消了他的录用，并与Yahoo取得联系，Yahoo也觉的Bill是个难得的人才，决定录用Bill，于是Yahoo就要取消一个实习生的录用申请。情况到了这个地步，已经乱成一团了，似乎完全不可控了。&lt;/p&gt;&lt;p class="nofont"&gt;&lt;span lang="zh-cn"&gt;于是Gale和Shapley提出了这个问题：给定一组雇主和申请人的之间的优先权，我们能否把申请人分配给雇主，以使得对每个雇主E，以及没分配为E工作的每个申请人A，至少我们下面两种情况之一成立？&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;E对他所接受的每个申请人比A更满意，或者&lt;/li&gt;&lt;li&gt;A对他目前的情况比其为雇主E更满意。&lt;/li&gt;&lt;/ul&gt;&lt;p class="sufont"&gt;2.问题形式化&lt;/p&gt;&lt;p class="nofont"&gt;了解这个概念的本质有助于使得这个问题尽可能的清晰，公司和申请人的世界包含了某些混乱的不均匀性。每个申请人可能申请多个公司，每个公司也可能录用多个人。我们排除这些因素，得到一个这个问题的本质。n个申请人的每个人对n个公司中的每个公司提出申请，每个公司想接受&lt;strong&gt;单一&lt;/strong&gt;的申请人。我们看到，这样做可以保留问题固有的基本特点，特别是我们对这个简化描述的解将被直接推广到更一般的情况。&lt;/p&gt;&lt;p class="nofont"&gt;沿着这个思路，我们提出另一个更明了的问题。n个男人和n个女人结婚，于是男人的集合是M={m1,m2,m3&amp;hellip;&amp;hellip;,mn}和女人集合是W={w1,w2,w3&amp;hellip;&amp;hellip;,wn}，令M&amp;times;W表示所有可能的形如{m,w}的有序对的集合，一个匹配S是来自M&amp;times;W的有序对的集合，并且有下述性质：每个M的成员和每个W的成员至多出现在S的一个有序对中，一个完美的S'具有下述性质：M的每个成员和W的每个成员恰好出现在S'的一个对里。&lt;/p&gt;&lt;p class="nofont"&gt;我们在这个背景下增加优先的概念，每个男人m&amp;isin;M对所有的女人排名，如果m给w的排名高于w'，我们就说&lt;strong&gt;m喜欢w超过w'&lt;/strong&gt;。我们把m的排序作为他的优先表，类似的，每个女人也有一个优先表。&lt;/p&gt;&lt;p class="nofont"&gt;在得到的优先表中，会存在稳定的匹配吗？看看下面的情况就知道了。&lt;/p&gt;&lt;p class="nofont"&gt;在S中存在两个对(m,w)(m',w')，他们具有m更喜欢w'而不喜欢w，w'更喜欢m而不喜欢m'。在这种情况下，我们说(m,w')是一个相对于S的不稳定因素。而我们的目标是得到一个不含有不稳定因素的婚姻集合。&lt;/p&gt;&lt;p class="nofont"&gt;那么我们怎么能得到这个稳定的集合呢？看看G-S算法的代码吧。&lt;/p&gt;&lt;p class="sufont"&gt;3.算法设计&lt;/p&gt;&lt;div class="mycode"&gt;初始所有的m&amp;isin;M和w&amp;isin;W都是自由的&lt;br/&gt;While 存在所有的男人m是自由的且还没对每个女人都求过婚&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;选择这样一个男人m&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;令w是m的优先表中m还没求过婚的最高排名的女人&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If w是自由的 then&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(m,w)变成约会状态&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Else w当前与m'约会&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If w是更喜欢m'而不喜欢m then&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m保持自由&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Else w是更喜欢m而不喜欢m'&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(m,w)变成约会状态&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m'变成自由&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;EndIf&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;EndIf&lt;br/&gt;EndWhile&lt;br/&gt;输出已约会的集合S&lt;br/&gt;&lt;/div&gt;&lt;p class="nofont"&gt;上面输出的集合S即稳定的匹配。&lt;/p&gt;&lt;p class="tifont"&gt;算法优化&lt;/p&gt;&lt;p align="left"&gt;传统G-S算法整个过程分为三步：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Initially,  make everyone take the starting status.&lt;/li&gt;&lt;li&gt;Do  Work, it take a loop one send a request and another receive and handle it&lt;/li&gt;&lt;li&gt;Finally,  the algorithm will terminate in condition of everyone is stable.&lt;/li&gt;&lt;/ul&gt;&lt;p class="nofont"&gt;因此，传统的G-S算法会在至多n^2次循环后结束，显然这不是最优化的。&lt;/p&gt;&lt;p class="sufont"&gt;1.算法初步探究&lt;/p&gt;&lt;p class="nofont"&gt;是什么影响了G-S算法的效率？&lt;br /&gt;      优化G-S算法，也就是优化循环的次数，那么必须搞清楚是什么影响了循环的次数。在典型的men-women问题上，我们得出影响循环次数的因素是当前free的人数，或是每进行一次循环man或woman从free到not free的人数，这个人数是0或是1，我称之为&amp;ldquo;约会效率&amp;rdquo;，即约会成功的可能性或是稳定性。       正常情况下，每进行一次循环，free man或free woman的数量减1或是不变。减1的情况下，约会的效率是最高的不单单是人数的减1，在未来的某个时候，m可能成为free，那么这一次成功的约会就为m减少了下次求婚人的数量（因为在这个规则中没有人会向把自己甩掉的前女友去求婚），贡献度为1/n。不变的情况下，free man或free woman的人数未变，但是减少了求婚列表仍未求婚的次数，贡献度为1/n。 &lt;/p&gt;&lt;p class="sufont"&gt;2.如何分析约会效率？ &lt;/p&gt;&lt;p class="nofont"&gt;从上面我们了解到了&amp;ldquo;约会效率&amp;rdquo;的概念，那么到底怎么去量化一个约会效率，怎么去改变约会效率是我们进一步要做的。 &lt;br /&gt;      首先，应该弄清什么是&amp;ldquo;约会效率&amp;rdquo;，在一个小节已经提过了，在这里再重申一遍，约会效率是每完成一次行为（循环行为）所对整个问题求解步数的贡献大小。在整个G-S算法过程中，我们把这个问题看做是可以找到最终解的（实际情况也是如此），那么在这个求解的过程中就必须的存在一个特定的&amp;ldquo;步数&amp;rdquo;或是时间，而每进行一次&amp;ldquo;行为&amp;rdquo;（一次循环中的求婚行为），就使我们前进一小步，逼近最终的解，那么这一小步就是这一次&amp;ldquo;行为&amp;rdquo;对整个问题的贡献。然而，一次&amp;ldquo;行为&amp;rdquo;所走的&amp;ldquo;一小步&amp;rdquo;并不是相等的，有可能一次&amp;ldquo;行为&amp;rdquo;A走的&amp;ldquo;一小步&amp;rdquo;要大一些，给它一个权值，比如5，而另一次&amp;ldquo;行为&amp;rdquo;B走的&amp;ldquo;一小步&amp;rdquo;要小一些，比如为1，显然&amp;ldquo;行为&amp;rdquo;A更好一些，我们总是期望一次&amp;ldquo;行为&amp;rdquo;能完成更多的事情。 &lt;br /&gt;      因此，如何计算&amp;ldquo;约会效率&amp;rdquo;是我们优化整个算法的关键。从上面我们可以很容易的想到，整体的&amp;ldquo;约会效率&amp;rdquo;跟每一步的&amp;ldquo;约会效率&amp;rdquo;有关，那么进行一次&amp;ldquo;行为&amp;rdquo;的&amp;ldquo;约会效率&amp;rdquo;怎么计算呢？我们知道进行一次&amp;ldquo;行为&amp;rdquo;有2种情况，变成not free的人数为0或是1，我们把它放的更普遍一些，每一次&amp;ldquo;行为&amp;rdquo;有4种情况，首先澄清几个术语，约会成功：指有一对人变成not free，约会失败：指没有人变成not free，有记忆：指对求过婚的人有记忆下次便不再求婚于他，无记忆：指对求过婚的人没有记忆下次求婚时找列表中最靠上的一个进行求婚。（有无记忆其实是我一个多虑，但考虑到在普通的问题中确实存在，所以把这个因素也考虑在内） &lt;/p&gt;&lt;p class="notetag"&gt;本文中多次提到free和not free，free指的是单身的男女，not free是当前进入约会状态的男女。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;约会失败-无记忆&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0%&lt;/li&gt;&lt;li&gt;约会失败-有记忆&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1/(n^2)%（n个man和n个woman形成n^2个组合，有记忆使得整体组合减1）&lt;/li&gt;&lt;li&gt;约会成功-无记忆&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;infin;0%&lt;/li&gt;&lt;li&gt;约会成功-有记忆 &amp;nbsp;&amp;nbsp;&amp;nbsp; 100%&lt;/li&gt;&lt;/ul&gt;&lt;p class="nofont"&gt;这四种情况后面跟的是它们的&amp;ldquo;约会效率&amp;rdquo;，对于无记忆的显然会使程序陷入死循环，所以效率极低。在men-women的案例中，使用的都是2、4情况。 &lt;/p&gt;&lt;p class="sufont"&gt;3.整体的效率和循环的次数&lt;/p&gt;&lt;p class="nofont"&gt;有了上面的每一步的&amp;ldquo;约会效率&amp;rdquo;，我们就可以求出整体的&amp;ldquo;约会效率&amp;rdquo;： &lt;br /&gt;      S=(x/n^2+y)/(x+y)*100%&lt;br /&gt;      &lt;strong&gt;n代表man或woman的人数，Number(man)==Number(woman)&lt;/strong&gt;&lt;br /&gt;      &lt;strong&gt;x代表&amp;ldquo;约会失败-有记忆&amp;rdquo;循环的次数&lt;/strong&gt;&lt;br /&gt;      &lt;strong&gt;y代表&amp;ldquo;约会成功-有记忆&amp;rdquo;循环的次数&lt;/strong&gt;&lt;br /&gt;      我们利用两个极限，便可以求出整体&amp;ldquo;约会效率&amp;rdquo;的最大值和最小值： &lt;br /&gt;      &lt;strong&gt;1/n&amp;lt;=整体效率&amp;lt;=1&lt;/strong&gt;&lt;br /&gt;      &lt;strong&gt;它们分别对应的循环次数为：n^2和n&lt;/strong&gt;&lt;br /&gt;      循环运行的次数为C，则： &lt;br /&gt;      &lt;strong&gt;C=n/S&lt;/strong&gt;&lt;/p&gt;&lt;p class="notetag"&gt;不知道细心的朋友发现问题没有，这里有一个陷阱，就是&lt;strong&gt;整体效率&lt;/strong&gt;是如何得出来的？我们只是知道整体效率的计算公式，却不知道怎么使用两个极限。这里，我做了一个假设，就是约会效率最好为1，在具体问题中,n个man和n个woman最小的循环次数为n，最大的循环次数为n^2，我假设了当循环次数为n时，整体效率为1，即假设了一个基数n，作为约会效率对比的约会基数，效率最高时，循环次数为n，整体效率为约会基数/n=1，而效率最低时，循环的次数为n^2，整体效率为约会基数/n^2=1/n。其实，整体效率是可以通过数学计算得来的，只不过现在条件还不够。&lt;/p&gt;&lt;p class="nofont"&gt;上面说到了整体效率的计算过程，我们发现其实，x和y的值也是有关系的，上面我曾说过整体效率还不能通过数学计算得出就是因为x和y的关系没有搞清楚。如果一个人总是失恋那么为了保持约会状态他肯定也总去约会。到底x和y是什么关系呢？我们设想一个场景，有ABC三名man和abc三名woman，ABC三名man对woman的列表都为abc，也就是说ABC三名man认为a最好，b次之，c最不好。同样，abc三名woman对man的列表都为ABC。下面是具体的情况： &lt;/p&gt;&lt;ul&gt;&lt;li&gt;每个man的求婚都能成功，也就是说没有man会被女朋友甩掉。 &lt;br /&gt;&lt;p class="nofont"&gt;A先向他列表中最好的a求婚，并约会成功；接着B向他列表中最好的a求婚，但a却不好抛弃现有的男友A去和B约会，因为a认为A比B更优秀，B最终与b约会成功；同样，C最终与c约会成功。 &lt;/p&gt;&lt;/li&gt;&lt;li&gt;每个man都会被别的man把女朋友给抢走，除非他是最后一个求婚的人。 &lt;br /&gt;&lt;p class="nofont"&gt;C先想他列表中最好的a求婚，a会欣然接受这次求婚；然后，B开始向自己列表中最好的a求婚，a发现B要比C更好，然后B与a约会成功，而C却失恋；随后，失恋的C发起另一轮求婚，这次他向b求婚，因为他已经向a求过婚了，而且是被a给甩掉的，显然b也会欣然接受这次求婚的，然后C与b约会成功；现在只剩下A还是单身了，于是A向自己列表中最好的a求婚，这时a发现A要比B好，于是她又甩掉了B，并且同A约会成功；然后单身的B开始向列表中第二位的b求婚，并且b会甩掉C跟B约会成功；然后单身的C向剩下的没有求婚的c求婚，并约会成功。 &lt;/p&gt;&lt;/li&gt;&lt;li&gt;这种情况比较特殊，A的列表为abc，B的为bac，C的为cab，a的为ABC，b的为BAC，c的为CAB，我们先后从ABC进行求婚，只需要进行3次便可以结束整个循环。 &lt;/li&gt;&lt;/ul&gt;&lt;p class="nofont"&gt;上面两种情况很典型。在第一种情况下，x的次数为3，y的次数为3，共进行了6次循环。第二种情况，x的次数为3，y的次数为6，第三者情况下，x的次数为0，y的次数为3。 &lt;br /&gt;      因此，我们总结出x和y的值域，n的取值便是x和y的定义域。 &lt;/p&gt;&lt;ul&gt;&lt;li&gt;x最小时，即&amp;ldquo;王八看绿豆&amp;rdquo;型，根本不需要盲目的求婚约会，x会是0。 &lt;/li&gt;&lt;li&gt;x最大时，即&amp;ldquo;癞蛤蟆想吃天鹅肉&amp;rdquo;型，时刻保持从&amp;ldquo;最癞的一只蛤蟆&amp;rdquo;开始向&amp;ldquo;最美的一只天鹅&amp;rdquo;求婚，x最大为1+2+3+&amp;hellip;&amp;hellip;+n-1=n(n-1)/2.&lt;/li&gt;&lt;li&gt;y最小时，即&amp;ldquo;一见钟情&amp;rdquo;型，进入约会状态后便不会再抛弃对方，y会是n。 &lt;/li&gt;&lt;li&gt;y最大时，即&amp;ldquo;见异思迁&amp;rdquo;型，老是更换约会对象，y会是1+2+3+&amp;hellip;&amp;hellip;+n=n(n+1)/2。 &lt;/li&gt;&lt;/ul&gt;&lt;p class="nofont"&gt;&lt;strong&gt;0&amp;lt;=x&amp;lt;=n(n-1)/2&lt;/strong&gt;&lt;br /&gt;      &lt;strong&gt;n&amp;lt;=y&amp;lt;=n(n+1)/2&lt;/strong&gt;&lt;br /&gt;      说到这里，我们可以用上面的几个公式验证一下。 &lt;/p&gt;&lt;p class="sufont"&gt;4.从约会效率下手优化算法&lt;/p&gt;&lt;p class="nofont"&gt;从上面我们得出，循环的次数与x和y的值有关，而x与y又是有一定联系的，那么什么情况下才是最优的G-S算法呢？当然是x的次数为0时的情况，那么我们怎么使得x的值尽量的小呢？很明显，我们必须知道x的大小代表着什么，X代表&amp;ldquo;约会失败-有记忆&amp;rdquo;循环的次数，那么为什么会约会失败呢？是因为当前的约会对象不够好，那么为了减小&amp;ldquo;约会失败&amp;rdquo;的次数，我们必须让每一个woman的约会对象足够好，&amp;ldquo;足够好&amp;rdquo;的概念是预计未来不会再有比当前约会对象更好的man来求婚了。我们定义一个新的词语叫&amp;ldquo;约会稳定性&amp;rdquo;，它指的是当前woman同当前的约会对象man约会到算法终止时的稳定程度，&amp;ldquo;约会稳定性&amp;rdquo;越大显然算法的效率就会越高，反之则越低。我们讨论2种情况： &lt;/p&gt;&lt;ul&gt;&lt;li&gt;x的次数为0，y的次数为n。 &lt;/li&gt;&lt;li&gt;x的次数为n*(n-1)/2，y的次数为n*(n+1)/2。 &lt;/li&gt;&lt;/ul&gt;&lt;p class="nofont"&gt;第一种情况是算法最优时的情况，即&amp;ldquo;约会稳定性&amp;rdquo;最高时的情形。第二种情况是算法最差时的情况，即&amp;ldquo;约会稳定性&amp;rdquo;最低时，每个人匆匆的约会后，又匆匆的抛弃对方。 &lt;br /&gt;      为了能够利用&amp;ldquo;约会稳定性&amp;rdquo;来控制算法的优略，我们需要进一步对&amp;ldquo;约会稳定性&amp;rdquo;探究。 &lt;/p&gt;&lt;p class="sufont"&gt;5.如何控制&amp;ldquo;约会稳定性&amp;rdquo;&lt;/p&gt;&lt;p class="nofont"&gt;在man-woman的案例中，到底什么样的约会才算是稳定的呢？好男人配好女人，坏男人配坏女人才是比较稳定的，所以整体的&amp;ldquo;约会稳定性&amp;rdquo;最大，就意味着相同等级的man去跟相同等级的woman约会。下面分几点进行阐述： &lt;/p&gt;&lt;ul&gt;&lt;li&gt;每个man都有一个对所有woman的优先列表，这些列表肯定的存在一定的差异，这些差异形成了我们想要的数据&amp;mdash;&amp;mdash;共识率A。共识率指示了man对所有woman整体偏好的差异程度，比如m1的列表为w1,w2，m2的列表为w1,w2，就说m1和m2对woman有一个共识，如果m2的列表为w2,w1，就说m1和m2对woman没有一个共识。同样的，woman也有一个这样的对man的共识率B。 &lt;/li&gt;&lt;li&gt;根据A判断出所有的man是否有一个可信的共识（这个比率的设定因人而异，通常要大于60%才能说有一个可信的共识），然后计算出men对women的平均排名A（有点像一个班的男生对自己班女生进行排名一样，这个排名是大家达成的共识），共识率越高，那么这个平均排名就越可信，反之，则不可取。同样的，women对men也有一个平均排名B。 &lt;/li&gt;&lt;li&gt;上面我们得出了平均排名A和平均排名B，我们又称AB为&amp;ldquo;稳定方向&amp;rdquo;，那么沿着&amp;ldquo;稳定方向&amp;rdquo;上的约会将是最稳定的，得出的&amp;ldquo;整体约会稳定性&amp;rdquo;会最高。因此，沿着这个&amp;ldquo;稳定方向&amp;rdquo;，依次选取free的man去向他列表中第一个为求过婚的woman求婚，得出的效率将是最优的。当然，这个&amp;ldquo;约会稳定性&amp;rdquo;也不是绝对的，可能一个人的优先列表与他人的完全不同，但有一点，在每一次循环时，我们总是选择最优秀的man去向他认为最优秀的woman求婚。 &lt;/li&gt;&lt;/ul&gt;&lt;p class="nofont"&gt;因此，我们得到一个优化的G-S算法。下面是优化的伪代码：&lt;/p&gt;&lt;div class="mycode"&gt;初始所有的m&amp;isin;M和w&amp;isin;W都是自由的&lt;br/&gt;&lt;strong&gt;if(M和W的共识率达到一定要求)&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;按照M和W对彼此的优先列表对M和W进行排序，形成&amp;ldquo;稳定方向&amp;rdquo;&lt;/strong&gt;&lt;br/&gt;While 存在所有的男人m是自由的且还没对每个女人都求过婚&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;选择这样一个男人m&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;令w是m的优先表中m还没求过婚的最高排名的女人&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If w是自由的 then&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(m,w)变成约会状态&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Else w当前与m'约会&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If w是更喜欢m'而不喜欢m then&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m保持自由&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Else w是更喜欢m而不喜欢m'&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(m,w)变成约会状态&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m'变成自由&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;EndIf&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;EndIf&lt;br/&gt;EndWhile&lt;br/&gt;输出已约会的集合S&lt;br/&gt;&lt;/div&gt;&lt;p class="nofont"&gt;上面的代码中加粗的代码是优化后的部分，我们发现整个过程跟传统的G-S算法是一样的，只不过在进行匹配之前进行了一些预处理工作。&lt;br /&gt;    具体优化后的性能如何呢？且看下回分解。&lt;/p&gt;&lt;p class="nofont"&gt;&lt;a href="http://www.cnblogs.com/niuchenglei/archive/2010/08/20/1804915.html"&gt;G-S匹配算法优化（1）&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.cnblogs.com/niuchenglei/archive/2010/08/23/1806754.html"&gt;G-S匹配算法优化（2）&lt;/a&gt;&lt;/p&gt;&lt;p class="warning"&gt;作者：Creason New(&lt;a target="_blank" href="http://www.cnblogs.com/niuchenglei"&gt;Creason's Blog&lt;/a&gt;)&lt;br /&gt; 出处：&lt;a target="_blank" href="http://www.cnblogs.com/niuchenglei"&gt; http://www.cnblogs.com/niuchenglei &lt;/a&gt;&lt;br /&gt; 本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/p&gt;&lt;/div&gt;&lt;script type="text/javascript" language="javascript"&gt;&lt;/script&gt;&lt;p&gt;&lt;noscript&gt;&lt;a href="http://www.51.la/?2866177" target="_blank"&gt;&lt;img alt="&amp;#x6211;&amp;#x8981;&amp;#x5566;&amp;#x514D;&amp;#x8D39;&amp;#x7EDF;&amp;#x8BA1;" src="http://img.users.51.la/2866177.asp" style="border:none" /&gt;&lt;/a&gt;&lt;/noscript&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/niuchenglei/aggbug/1804915.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/niuchenglei/archive/2010/08/20/1804915.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/niuchenglei/archive/2010/08/15/1800179.html</id><title type="text">ASP.NET MVC之视图引擎</title><summary type="text">最近微软发布了另外一个在ASP.NET MVC上应用的视图引擎Razor。通过前面一系列的探讨，我想大部分都了解了ASP.NET MVC整个的原理，包括TempData、ViewData、ModelBinding、Filter等，但是我们还不是太了解它的视图引擎的情况。ASP.NET MVC的视图引擎具有非常好的扩展性，我们可以使用其它的视图引擎代替WebForm，或是同时使用多种试图引擎，这些都...</summary><published>2010-08-15T12:14:00Z</published><updated>2010-08-15T12:14:00Z</updated><author><name>Creason New</name><uri>http://www.cnblogs.com/niuchenglei/</uri></author><link rel="alternate" href="http://www.cnblogs.com/niuchenglei/archive/2010/08/15/1800179.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/niuchenglei/archive/2010/08/15/1800179.html"/><content type="html">&lt;div class="link"&gt;&lt;a name="top" id="top"&gt;&lt;/a&gt;&lt;p class="nofont"&gt;最近微软发布了另外一个在ASP.NET MVC上应用的视图引擎Razor。通过前面一系列的探讨，我想大部分都了解了ASP.NET MVC整个的原理，包括TempData、ViewData、ModelBinding、Filter等，但是我们还不是太了解它的视图引擎的情况。ASP.NET MVC的视图引擎具有非常好的扩展性，我们可以使用其它的视图引擎代替WebForm，或是同时使用多种试图引擎，这些都得益于ASP.NET MVC精美的设计，下面我们一起来观赏一下它的设计。&lt;/p&gt;&lt;p class="tifont"&gt;内容概览&lt;a href="#top"&gt;Top&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="#title1"&gt;ActionResult做了什么？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#title2"&gt;最具代表性的ViewResult&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#title3"&gt;ASP.NET MVC的视图引擎&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;a name="title1" id="title1"&gt;&lt;/a&gt;&lt;p class="tifont"&gt;ActionResult做了什么？&lt;a href="#top"&gt;Top&lt;/a&gt;&lt;/p&gt;&lt;p class="nofont"&gt;讲到视图引擎，不得不说ActionResult，因为在Controller中，我们看不到一点视图引擎的影子，唯一提供线索的只有ActionResult，所以我们必须先从AcionResult下手。&lt;/p&gt;&lt;p class="nofont"&gt;下面是ASP.NET MVC提供的所有的ActionResult类型的类图：&lt;/p&gt;&lt;img src="http://pic002.cnblogs.com/img/niuchenglei/201008/2010081520101146.jpg" width="700" height="400" /&gt;&lt;p class="nofont"&gt;这其中用的最多的是ViewResult,ActionResult有一个抽象方法ExecuteResult，这个方法会向用户的请求中写入要输出的内容，比如Response.Write等操作。&lt;/p&gt;&lt;a name="title2" id="title2"&gt;&lt;/a&gt;&lt;p class="tifont"&gt;最具代表性的ViewResult&lt;a href="#top"&gt;Top&lt;/a&gt;&lt;/p&gt;&lt;p class="nofont"&gt;在ASP.NET MVC中，ViewResult用的最多，Controller有一个View方法，它来实例化一个ViewResult对象，并返回。下面是View方法：&lt;/p&gt;&lt;div class="mycode"&gt;protected internal virtual ViewResult View(string viewName, string masterName, object model) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (model != null) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ViewData.Model = model;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return new ViewResult {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ViewName = viewName,&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MasterName = masterName,&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ViewData = ViewData,&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TempData = TempData&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};&lt;br/&gt;}&lt;/div&gt;&lt;p class="nofont"&gt;它实例化一个ViewResult对象，并对其ViewData、TempData赋值，以完成从Controller向页面的传值。&lt;/p&gt;&lt;p class="nofont"&gt;ViewResult继承自ViewResultBase,ViewResult有一个IView类型的View属性，IView接口只有一个方法：&lt;/p&gt;&lt;div class="mycode"&gt;public interface IView {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void Render(ViewContext viewContext, TextWriter writer);&lt;br/&gt;}&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="nofont"&gt;因此，我们推测IView用于输出内容给用户。ViewResult类的ExecuteResult方法证明了这一点：&lt;/p&gt;&lt;div class="mycode"&gt;public override void ExecuteResult(ControllerContext context) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (context == null) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw new ArgumentNullException("context");&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (String.IsNullOrEmpty(ViewName)) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ViewName = context.RouteData.GetRequiredString("action");&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ViewEngineResult result = null;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (View == null) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result = FindView(context);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;View = result.View;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;View.Render(viewContext, context.HttpContext.Response.Output);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (result != null) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result.ViewEngine.ReleaseView(context, View);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;}&lt;br/&gt;    &lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&lt;a name="title3" id="title3"&gt;&lt;/a&gt;&lt;p class="tifont"&gt;ASP.NET MVC的视图引擎&lt;a href="#top"&gt;Top&lt;/a&gt;&lt;/p&gt;&lt;p class="nofont"&gt;从上一小节中，看到要想得到IView对象，必须先有ViewEngineResult对象，而ViewEngineResult对象是通过ViewResult类的FindView方法得到的：&lt;/p&gt;&lt;div class="mycode"&gt;protected override ViewEngineResult FindView(ControllerContext context) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (result.View != null) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return result;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// we need to generate an exception containing all the locations we searched&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringBuilder locationsText = new StringBuilder();&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;foreach (string location in result.SearchedLocations) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;locationsText.AppendLine();&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;locationsText.Append(location);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture,&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MvcResources.Common_ViewNotFound, ViewName, locationsText));&lt;br/&gt;}&lt;br/&gt;    &lt;/div&gt;&lt;p class="nofont"&gt;从ViewResult类的FindView方法中，得知ViewEngineResult是通过ViewEngineCollection的FindView得到的，而ViewEngineCollection正是ViewEngines的静态属性Engines,Engines返回一个只有一个WebFormViewEngine类型实例的一个集合。所以，ViewEngineResult会是调用WebFormViewEngine类的FindView方法返回的结果。如果ViewEngins的静态属性Engines有多个ViewEngine提供，那么就依次遍历它们直到找到第一个不为空的ViewEngineResult为止。这样我们就可以在同一个MVC网站中使用多种视图引擎了。&lt;/p&gt;&lt;p class="nofont"&gt;在WebFormViewEngine的FindView方法返回之前，它会为ViewEngineResult注入一个IView类型的WebFormView实例，这样ViewEngineResult就作为一个中间人把IView类型给ViewResult了，然后ViewResult借助IView的力量，把数据输出给用户。&lt;/p&gt;&lt;p class="nofont"&gt;它们的关系是：&lt;/p&gt;&lt;img src="http://pic002.cnblogs.com/img/niuchenglei/201008/2010081520110671.jpg" /&gt;&lt;p class="warning"&gt;作者：Creason New(&lt;a href="http://www.cnblogs.com/niuchenglei" target="_blank"&gt;Creason's Blog&lt;/a&gt;)&lt;br /&gt; 出处：&lt;a href="http://www.cnblogs.com/niuchenglei" target="_blank"&gt; http://www.cnblogs.com/niuchenglei &lt;/a&gt;&lt;br /&gt; 本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/p&gt;&lt;/div&gt;&lt;script language="javascript" type="text/javascript"&gt;&lt;/script&gt;&lt;p&gt;&lt;noscript&gt;&lt;a href="http://www.51.la/?2866177" target="_blank"&gt;&lt;img alt="&amp;#x6211;&amp;#x8981;&amp;#x5566;&amp;#x514D;&amp;#x8D39;&amp;#x7EDF;&amp;#x8BA1;" src="http://img.users.51.la/2866177.asp" style="border:none" /&gt;&lt;/a&gt;&lt;/noscript&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/niuchenglei/aggbug/1800179.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/niuchenglei/archive/2010/08/15/1800179.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/niuchenglei/archive/2010/07/22/1783310.html</id><title type="text">ASP.NET MVC之Action的执行</title><summary type="text">内容概览Top先说说FilterFilter和Action的执行万总归一——ActionResult先说说FilterTopFilter是的重要性不言而喻，作为AOP的一种实践，虽然Filter的类型不尽相同，执行的时间也不太一样，但有一个共同点就是围绕着Action做文章。所以，Action的执行是离不开Filter的，说到Action必须先明白Filter。ASP.NE...</summary><published>2010-07-22T13:51:00Z</published><updated>2010-07-22T13:51:00Z</updated><author><name>Creason New</name><uri>http://www.cnblogs.com/niuchenglei/</uri></author><link rel="alternate" href="http://www.cnblogs.com/niuchenglei/archive/2010/07/22/1783310.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/niuchenglei/archive/2010/07/22/1783310.html"/><content type="html">&lt;div class="link"&gt;&lt;a id="top" name="top"&gt;&lt;/a&gt;&lt;p class="nofont"&gt;&amp;nbsp;&lt;/p&gt;&lt;p class="tifont"&gt;内容概览&lt;a href="#top"&gt;Top&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="#title1"&gt;先说说Filter&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#title2"&gt;Filter和Action的执行&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#title3"&gt;万总归一&amp;mdash;&amp;mdash;ActionResult&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;a id="title1" name="title1"&gt;&lt;/a&gt;&lt;p class="tifont"&gt;先说说Filter&lt;a href="#top"&gt;Top&lt;/a&gt;&lt;/p&gt;&lt;p class="nofont"&gt;Filter是的重要性不言而喻，作为AOP的一种实践，虽然Filter的类型不尽相同，执行的时间也不太一样，但有一个共同点就是围绕着Action做文章。所以，Action的执行是离不开Filter的，说到Action必须先明白Filter。&lt;/p&gt;&lt;p class="nofont"&gt;ASP.NET MVC有这么几种类型的Filter：在Action前后执行的IActionFilter，在ActionResult返回前后执行的IResultFilter，验证作用的IAuthorizationFilter，捕获异常的IExceptionFilter。平时用到的大多是前三种。它们实行时要依赖一个上下文对象XXXContext，XXXContext继承自ControllerContext，还扩展了一些自己的属性。Filter在运行时的获取和分类在上一篇中已经介绍过了。&lt;/p&gt;&lt;a id="title2" name="title2"&gt;&lt;/a&gt;&lt;p class="tifont"&gt;Filter和Action的执行&lt;a href="#top"&gt;Top&lt;/a&gt;&lt;/p&gt;&lt;p class="nofont"&gt;在Controller类的InvokeAction方法中，我们先是获取了ControllerDescriptor再是ActionDescriptor，然后又获取到了所有的Filter，并把它们分门别类的存了起来。这么多的准备工作终于完成了，下一步就是执行Action和Filter了。&lt;/p&gt;&lt;p class="nofont"&gt;在InvokeAction方法中，有一段try...catch语句，这段就是执行Action和Filter的语句了。&lt;/p&gt;&lt;div class="mycode"&gt;try {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AuthorizationContext authContext = &lt;span style="color: red;"&gt;①InvokeAuthorizationFilters&lt;/span&gt;(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (authContext.Result != null) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// the auth filter signaled that we should let it short-circuit the request&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: red;"&gt;②InvokeActionResult&lt;/span&gt;(controllerContext, authContext.Result);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (controllerContext.Controller.ValidateRequest) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ValidateRequest(controllerContext.HttpContext.Request);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;IDictionary&amp;lt;string, object&amp;gt; parameters = GetParameterValues(controllerContext, actionDescriptor);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ActionExecutedContext postActionContext = &lt;span style="color: red;"&gt;③InvokeActionMethodWithFilters&lt;/span&gt;(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: red;"&gt;④InvokeActionResultWithFilters&lt;/span&gt;(controllerContext, filterInfo.ResultFilters, postActionContext.Result);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;}&lt;br/&gt;catch (ThreadAbortException) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// This type of exception occurs as a result of Response.Redirect(), but we special-case so that&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// the filters don't see this as an error.&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw;&lt;br/&gt;}&lt;br/&gt;catch (Exception ex) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// something blew up, so execute the exception filters&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ExceptionContext exceptionContext = &lt;span style="color: red;"&gt;⑤InvokeExceptionFilters&lt;/span&gt;(controllerContext, filterInfo.ExceptionFilters, ex);&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (!exceptionContext.ExceptionHandled) {&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw;&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: red;"&gt;⑥InvokeActionResult&lt;/span&gt;(controllerContext, exceptionContext.Result);&lt;br/&gt;}&lt;br/&gt;    &lt;/div&gt;&lt;p class="nofont"&gt;我们知道有的Filter是在Action执行之前执行，有的则是其后，那么这几种类型Filter执行的顺序是IAuthorizationFilter, IResultFilter, IActionFilter, IActionFilter, IResultFilter.&lt;/p&gt;&lt;p class="nofont"&gt;所以先执行上面代码中的①，InvokeAuthorizationFilters方法也很简单，就是遍历得到的AuthorizationFilter的集合，执行每一个Filter的OnAuthorize方法，如何Result!=null，就说明没有验证通过，执行②，如果验证通过，则执行③④，③④的作用是执行Action和Filter。如果有异常发生，就执行⑤⑥。&lt;/p&gt;&lt;p class="nofont"&gt;就这样，Action和Filter就都执行完毕了。&lt;/p&gt;&lt;a id="title3" name="title3"&gt;&lt;/a&gt;&lt;p class="tifont"&gt;万总归一&amp;mdash;&amp;mdash;ActionResult&lt;a href="#top"&gt;Top&lt;/a&gt;&lt;/p&gt;&lt;p class="nofont"&gt;我们Go To Defination到上面的5个方法，发现除了InvokeActionMethodWithFilter之外其它方法都最终调用到了InvokeActionResult方法。InvokeActionResult只有一行语句：&lt;/p&gt;&lt;div class="mycode"&gt;actionResult.ExecuteResult(controllerContext);&lt;/div&gt;&lt;p class="nofont"&gt;ActionResult类是一个抽象类，Action返回用户的类型也必须是ActionResult类型的，ActionResult抽象了视图引擎的所有返回类型。最终，天下大一统，给用户输出的任务就交给了ActionResult，而我们的视图引擎会搞好这一切。&lt;/p&gt;&lt;p class="warning"&gt;作者：Creason New(&lt;a target="_blank" href="http://www.cnblogs.com/niuchenglei"&gt;Creason's Blog&lt;/a&gt;)&lt;br /&gt; 出处：&lt;a target="_blank" href="http://www.cnblogs.com/niuchenglei"&gt; http://www.cnblogs.com/niuchenglei &lt;/a&gt;&lt;br /&gt; 本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/p&gt;&lt;/div&gt;&lt;script type="text/javascript" language="javascript"&gt;&lt;/script&gt;&lt;p&gt;&lt;noscript&gt;&lt;a href="http://www.51.la/?2866177" target="_blank"&gt;&lt;img alt="&amp;#x6211;&amp;#x8981;&amp;#x5566;&amp;#x514D;&amp;#x8D39;&amp;#x7EDF;&amp;#x8BA1;" src="http://img.users.51.la/2866177.asp" style="border:none" /&gt;&lt;/a&gt;&lt;/noscript&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/niuchenglei/aggbug/1783310.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/niuchenglei/archive/2010/07/22/1783310.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/niuchenglei/archive/2010/03/12/1684683.html</id><title type="text">ModelBinder机制</title><summary type="text">ModelBinder在asp.net mvc中可以算是一个亮点，有了ModelBinder我们就可以大胆的传递各种类型的参数给Action了，这些都要归功于强大的DefaultModelBinder，当然它也不是万能的，有时候我们还是需要自己亲手写一个自己的ModelBinder，那么在实际中，ModelBinder的机制是怎么样的呢？当然您完全可以不关心这个而开发出一样漂亮的程序，但我们是孜孜...</summary><published>2010-03-12T11:31:00Z</published><updated>2010-03-12T11:31:00Z</updated><author><name>Creason New</name><uri>http://www.cnblogs.com/niuchenglei/</uri></author><link rel="alternate" href="http://www.cnblogs.com/niuchenglei/archive/2010/03/12/1684683.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/niuchenglei/archive/2010/03/12/1684683.html"/><content type="text">ModelBinder在asp.net mvc中可以算是一个亮点，有了ModelBinder我们就可以大胆的传递各种类型的参数给Action了，这些都要归功于强大的DefaultModelBinder，当然它也不是万能的，有时候我们还是需要自己亲手写一个自己的ModelBinder，那么在实际中，ModelBinder的机制是怎么样的呢？当然您完全可以不关心这个而开发出一样漂亮的程序，但我们是孜孜...</content></entry><entry><id>http://www.cnblogs.com/niuchenglei/archive/2010/03/06/1679915.html</id><title type="text">强大的Filter</title><summary type="text">这是接着以前一个系列的文章，由于放假期间把全部精力都放在了玩上，所以就耽搁了好长时间，从现在开始，继续我的asp.net mvc源代码之旅。内容概览Top本篇主要探讨一下mvc一个重要的功能——Filter，我们通过研究源代码来了解Filter的原理，以及AOP模式和各种Filter的执行。最重要的是大家通过理解Filter的代码，明白Filter的机制，从而对Filter...</summary><published>2010-03-06T13:23:00Z</published><updated>2010-03-06T13:23:00Z</updated><author><name>Creason New</name><uri>http://www.cnblogs.com/niuchenglei/</uri></author><link rel="alternate" href="http://www.cnblogs.com/niuchenglei/archive/2010/03/06/1679915.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/niuchenglei/archive/2010/03/06/1679915.html"/><content type="text">这是接着以前一个系列的文章，由于放假期间把全部精力都放在了玩上，所以就耽搁了好长时间，从现在开始，继续我的asp.net mvc源代码之旅。内容概览Top本篇主要探讨一下mvc一个重要的功能——Filter，我们通过研究源代码来了解Filter的原理，以及AOP模式和各种Filter的执行。最重要的是大家通过理解Filter的代码，明白Filter的机制，从而对Filter...</content></entry><entry><id>http://www.cnblogs.com/niuchenglei/archive/2010/03/03/1677494.html</id><title type="text">递归与迭代那些事儿</title><summary type="text">递归和迭代是算法中十分重要的一块，最近我在读《计算机程序的构造和解释》时就遇到了这么一个问题，书中对一个问题使用了递归和迭代两个方法，然后对两者进行了分析比对。我针对这个问题做了一个切实的试验，发现测试结果与我想的，乃至大家想的相差甚远。内容概览Top问题的描述解决问题的两个方案两个方案的分析真刀真枪的试验问题的描述Top问题很常见，就是求阶乘，6的阶乘就是6*5*4*3*2*1。解决问题的两个方...</summary><published>2010-03-03T12:47:00Z</published><updated>2010-03-03T12:47:00Z</updated><author><name>Creason New</name><uri>http://www.cnblogs.com/niuchenglei/</uri></author><link rel="alternate" href="http://www.cnblogs.com/niuchenglei/archive/2010/03/03/1677494.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/niuchenglei/archive/2010/03/03/1677494.html"/><content type="text">递归和迭代是算法中十分重要的一块，最近我在读《计算机程序的构造和解释》时就遇到了这么一个问题，书中对一个问题使用了递归和迭代两个方法，然后对两者进行了分析比对。我针对这个问题做了一个切实的试验，发现测试结果与我想的，乃至大家想的相差甚远。内容概览Top问题的描述解决问题的两个方案两个方案的分析真刀真枪的试验问题的描述Top问题很常见，就是求阶乘，6的阶乘就是6*5*4*3*2*1。解决问题的两个方...</content></entry><entry><id>http://www.cnblogs.com/niuchenglei/archive/2010/01/10/1643625.html</id><title type="text">SixthSense（第六感）技术猜测</title><summary type="text">相信这段视频大家都看过了，真是非常令人震撼，我连续看了三遍，每一遍都有不同的理解。创新，一个我们多次提到的词语，在不断的上演着。内容概览Top贴一个优酷的视频连接SixthSense的几个技术点从SixthSense我们想到的贴一个优酷的视频连接Top视频：SixthSense惊人的潜力 by PranavMistrySixthSense的几个技术点Top一个伟大的创新，在您看完这段视频之后是否应...</summary><published>2010-01-10T11:19:00Z</published><updated>2010-01-10T11:19:00Z</updated><author><name>Creason New</name><uri>http://www.cnblogs.com/niuchenglei/</uri></author><link rel="alternate" href="http://www.cnblogs.com/niuchenglei/archive/2010/01/10/1643625.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/niuchenglei/archive/2010/01/10/1643625.html"/><content type="text">相信这段视频大家都看过了，真是非常令人震撼，我连续看了三遍，每一遍都有不同的理解。创新，一个我们多次提到的词语，在不断的上演着。内容概览Top贴一个优酷的视频连接SixthSense的几个技术点从SixthSense我们想到的贴一个优酷的视频连接Top视频：SixthSense惊人的潜力 by PranavMistrySixthSense的几个技术点Top一个伟大的创新，在您看完这段视频之后是否应...</content></entry></feed>
