百万年薪的算法题解决方法

<p><span>这个问题的地址是:<a href="http://mitibar.com/superdrink.php" target="_blank">http://mitibar.com/superdrink.php</a></span></p>
<p><span>我只是解决了这个问题,并无入职那个公司的打算。</span></p>
<p></p>
<p><span><span style="font-family: mceinline;">第一种是:遗传算法</span></span></p>
<p><span></span></p>
<div>这个问题可以抽象成数学模型是这样的:</div>
<div>我有一个有向图G,他有n个节点,其中任意一个节点a都有到另外n-1个节点的路径!</div>
<div>例如3个节点的图可以这样解释:(图差不进去)</div>
<div></div>
<p></p>
<p></p>
<div>箭头我没画,太难了,呵呵!每个路径上有一定的费用,我们要经过每个点,然后回到起点(起点是任意的),经过的点可以重复,并且要产生的费用最小。</div>
<div>这个我个人觉得问题有点难,很像哈密顿路径问题,但是又不是太像。我们暂时称我们要寻找的路径为A路径。我用动态规划没有规划出来,贪心算法有没有最优子结构,虽然有重叠字问题!于是我想到了用遗传算法,关于算法的杂交和变异算子(核心函数),我是这样想的:</div>
<div></div>
<div>我们肯定要自己生成几个染色体(就是它的A路径),其中一定要加的是顺时针和逆时针的路径!因为我们总共有n!(n的阶乘)条边,其中我们至少选择n-1条边才能连接n个节点,只有顺时针和逆时针满足这种情况!然后我们在随便挑选几个路径。</div>
<div></div>
<div>关于杂交:</div>
<div>我是这样想的,假设我们有7个节点,分别是1,2,3,4,5,6,7我们随机挑选这两个染色体,当然我们用赌轮选择法选择,我们把每个路径的费用相加,然后取倒数就可以了!这样,费用越小的我们选择的空间越大,当然,我们是精英选择,也就是只从前5%优秀的基因(就是倒数最大的前5%),其他的不选择。假设我们选择了</div>
<div></div>
<div> 染色体A:1,2,3,4,5,6,7,1</div>
<div> 染色体B:1,<span style="color: #ff0000;">4</span>,2,<span style="color: #ff0000;">5</span>,<span style="color: #ff0000;">3</span>,<span style="color: #ff0000;">7,</span>6,1</div>
<div></div>
<div>忘了介绍我们的排序方式,1,2,3表示先从1到2,再从2到3,为了简单表示,我们表示成-12,就像高中的向量,向量12加上向量23,等于向量13,所以呢,1,4,2,3表示,-14,-42,-23,也就是从1到2的代价太大了,我们不得不绕道4。好了杂交开始了:</div>
<div>我们先从B中随机的选择4个节点,节点不能重复,红色就是我们选择的节点,我们随机的在我们选择到的节点中选择一个,例如是4,然后在在剩下的三个节点中选择一个,例如7,然后再A中交换4和7的位置,依次类推,只到了我们选中的节点数都被选光。</div>
<div></div>
<div>对B则采用相同的方法,只不过我们从B选择,另外,您觉得可能这个没有杂交,毕竟我们接触遗传算法都是A和B估计得互换一部分自己的染色体,但是,我们遗传算法是采用生物学模拟的,我们的染色体表示一个形状,比如比如耳朵大小,这就像我们的A路径一样,我们每次遗传给下一代,都会有我们耳朵的基因,这就像我们每次都会满足A路径的要求,要是不满足,就相当于给了下一代一个不完整的耳朵,你也看出来了,我们A和B并没有互换染色体,这就相当于动物没有交配就形成了下一代,呵呵,我的看法是,我们的遗传算法是要满足A路径的需求,寻找最优解,没必要完全按照生物上的来,这就是计算机的乐趣!</div>
<div></div>
<div>基因突变:</div>
<div>突变的概率是很低的,我们假设是0.001,怎么突变,</div>
<div></div>
<div> 染色体A:1,<span style="color: #ff0000;">2</span>,3,4,5,6,7 ,1</div>
<div></div>
<div>假设红色为不幸突变的基因,那么我们就把这个加上一个路径,删除多余的那个路径,比如变成了</div>
<div></div>
<div> 染色体B:1,<span style="color: #ff0000;">4</span>,<span style="color: #ff0000;">2</span>,3,5,6,7,1</div>
<div></div>
<div>就相当于-14然后再-42,当然我们每次突变都能完成A路径的需求,而不是产生残次品,浪费宝贵的CPU资源!</div>
<div>然后遗传算法会收缩,知道我们确定了最小的值,但是这个还是有概率的!</div>
<div></div>
<div>我们可以建议一个链表,然后再这个链表达到了最大的容量的时候,我们就找到路径费用最大的那条染色体设为A,和要加入链表的染色体B作比较,如果A比B费用高,我们就剔除A,加入B,如果小,直接删除B。</div>
<div></div>
<div>第二种:贪心算法</div>
<div></div>
<div>
<p class="MsoNormal">我们还是模拟成数学问题:</p>
<p class="MsoNormal">我有一个有向图<span lang="EN-US">G</span>,他有<span lang="EN-US">n</span>个节点,其中任意一个节点<span lang="EN-US">a</span>都有到另外<span lang="EN-US">n-1</span>个节点的路径!每个路径上有一定的费用,我们要经过每个点,然后回到起点(起点是任意的),经过的点可以重复,并且要产生的费用最小。<span lang="EN-US"></span></p>
<p class="MsoNormal">如图三个节点的图:</p>
<p class="MsoNormal">
</p>
<p class="MsoNormal">这次,我们是运用贪心算法给出答案:<span lang="EN-US"></span></p>
<p class="MsoNormal">我们设函数<span lang="EN-US">f</span>(<span lang="EN-US">n</span>)为必须求出<span lang="EN-US">n</span>个节点的路径。设函数<span lang="EN-US">g</span>(<span lang="EN-US">n</span>,<span lang="EN-US">m</span>)是节点<span lang="EN-US">n</span>到节点<span lang="EN-US">m</span>的路径的大小,某种原料由机器<span lang="EN-US">n</span>到机器<span lang="EN-US">m</span>所转化所花的机器设备的钱。我们再设集合<span lang="EN-US">B</span>(<span lang="EN-US">n</span>,<span lang="EN-US">m</span>)是<span lang="EN-US">{g</span>(<span lang="EN-US">1</span>,<span lang="EN-US">m</span>),<span lang="EN-US">g</span>(<span lang="EN-US">2</span>,<span lang="EN-US">m</span>),<span lang="EN-US">…</span>,<span lang="EN-US">g</span>(<span lang="EN-US">n</span>,<span lang="EN-US">m</span>)<span lang="EN-US">}</span>,他表示是节点<span lang="EN-US">1</span>到节点<span lang="EN-US">n</span>和节点<span lang="EN-US">m</span>的所有路径的集合。设集合<span lang="EN-US">A</span>(<span lang="EN-US">n</span>,<span lang="EN-US">m</span>)是<span lang="EN-US">{g</span>(<span lang="EN-US">n</span>,<span lang="EN-US">1</span>),<span lang="EN-US">g</span>(<span lang="EN-US">n</span>,<span lang="EN-US">2</span>),<span lang="EN-US">…</span>,<span lang="EN-US">g</span>(<span lang="EN-US">n</span>,<span lang="EN-US">m</span>)<span lang="EN-US">}</span>的集合,他表示节点<span lang="EN-US">n</span>和节点<span lang="EN-US">1</span>到节点<span lang="EN-US">m</span>的集合。设我们要寻找的路径为<span lang="EN-US">A</span>路径,也就是花费最少的钱。<span lang="EN-US"></span></p>
<p class="MsoNormal">然后我们就可以回顾一下贪心算法的四个步骤:<span lang="EN-US"></span></p>
<p class="MsoListParagraph"><!--[if !supportLists]--><span lang="EN-US">1,
</span><!--[endif]-->寻找最优子结构。<span lang="EN-US"></span></p>
<p class="MsoListParagraph"><!--[if !supportLists]--><span lang="EN-US">2,
</span><!--[endif]-->递归描述最优子结构。<span lang="EN-US"></span></p>
<p class="MsoListParagraph"><!--[if !supportLists]--><span lang="EN-US">3,
</span><!--[endif]-->证明递归式的正确性。<span lang="EN-US"></span></p>
<p class="MsoListParagraph"><!--[if !supportLists]--><span lang="EN-US">4,
</span><!--[endif]-->写代码。<span lang="EN-US"></span></p>
<p class="MsoNormal">首先我们来看第一:寻找最优子结构<span lang="EN-US"></span></p>
<p class="MsoNormal">我们要寻找<span lang="EN-US">f</span>(<span lang="EN-US">n</span>)的<span lang="EN-US">A</span>路径,首先,我们可以想到,要求<span lang="EN-US">n</span>个节点的<span lang="EN-US">A</span>路径,我们能不能求一个<span lang="EN-US">n-1</span>节点的<span lang="EN-US">A</span>路径呢?然后再求<span lang="EN-US">n-2</span>的<span lang="EN-US">A</span>路径,然后是<span lang="EN-US">n-3</span>的<span lang="EN-US">A</span>路径,以此类推,知道节点数剩下最后两个。求出这两个节点的<span lang="EN-US">A</span>路径,我们就依次的先上走,直到求出了<span lang="EN-US">n</span>个节点的<span lang="EN-US">A</span>路径。<span lang="EN-US"></span></p>
<p class="MsoNormal">第二:递归描述最优子结构<span lang="EN-US"></span></p>
<p class="MsoNormal">根据我们上面的描述,我们可以这样求解我们的递归式:<span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US">f</span>(<span lang="EN-US">n</span>)<span lang="EN-US">=f</span>(<span lang="EN-US">n-1</span>)<span lang="EN-US">+ </span><span lang="EN-US">min</span><span lang="EN-US"> </span>(<span lang="EN-US">B</span>(<span lang="EN-US">n-1</span>,<span lang="EN-US">n</span>))<span lang="EN-US">+ </span><span lang="EN-US">min</span><span lang="EN-US"> </span>(<span lang="EN-US">A</span>(<span lang="EN-US">n</span>,<span lang="EN-US">n-1</span>))<span lang="EN-US">- </span>(<span lang="EN-US">when X=Y</span>)<span lang="EN-US">g</span>(<span lang="EN-US">X</span>,<span lang="EN-US">Y</span>)<span lang="EN-US"></span></p>
<p class="MsoNormal">递归式有点复杂,不是吗?好了,我来解释一下,<span lang="EN-US">f</span>函数和集合<span lang="EN-US">B</span>前面是我们定义过的,那么<span lang="EN-US">min</span>是从集合<span lang="EN-US">B</span>中选出最小的值。简单点说,第一个<span lang="EN-US">min</span>是选出的是<span lang="EN-US">n-1</span>个节点到<span lang="EN-US">n</span>最小的路径,第二个<span lang="EN-US">min</span>是选出的是节点<span lang="EN-US">n</span>到已知的<span lang="EN-US">n-1</span>个节点的最小的路径,我们就是要找这两个路径。然后加上<span lang="EN-US">f</span>(<span lang="EN-US">n-1</span>)就是<span lang="EN-US">n</span>个节点的路径了。好了,该解释什么是<span lang="EN-US">g</span>(<span lang="EN-US">X</span>,<span lang="EN-US">Y</span>)了,我们设<span lang="EN-US">X</span>代表从<span lang="EN-US">min </span>(<span lang="EN-US">B</span>(<span lang="EN-US">n-1</span>,<span lang="EN-US">n</span>))中选出的那个值得节点,而<span lang="EN-US">Y</span>代表<span lang="EN-US">min</span>(<span lang="EN-US">A</span>(<span lang="EN-US">n</span>,<span lang="EN-US">n-1</span>))中选出的节点。我们必须减去这两个节点的路径。</p>
<p class="MsoNormal">
</p>
<p class="MsoNormal">但是我们不要忘了另外一种情况,就是<span lang="EN-US">X</span>和<span lang="EN-US">Y</span>相等时的节点,这时,我们回在计算<span lang="EN-US">A</span>(<span lang="EN-US">n</span>,<span lang="EN-US">n-1</span>)的第二小的边,然后让他和<span lang="EN-US">Y</span>加上<span lang="EN-US">g</span>(<span lang="EN-US">n-1,n</span>)比较大小,如果前者大,则选择后者,就是说我们还得加上<span lang="EN-US">g</span>(<span lang="EN-US">X,Y</span>)的大小,如果后者大,则选择前者。所以我在<span lang="EN-US">g</span>(<span lang="EN-US">X</span>,<span lang="EN-US">Y</span>)前面加上了(<span lang="EN-US">when X=Y</span>)。(在图中用红色表示如果选择完了,如下图,这说明由<span lang="EN-US">A</span>到<span lang="EN-US">C</span>和由<span lang="EN-US">C</span>到<span lang="EN-US">A</span>是相等的费用)</p>
<p class="MsoNormal">
</p>
<p class="MsoNormal">千万不要忘了结束递归的条件:<span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US">If n=2 return</span>;<span lang="EN-US"></span></p>
<p class="MsoNormal">第三:证明递归式的正确性<span lang="EN-US"></span></p>
<p class="MsoNormal">这个说实话,也很好证明,我们采取数学归纳法,<span lang="EN-US"></span></p>
<p class="MsoNormal">当<span lang="EN-US">n=2</span>时,递归式成立。<span lang="EN-US"></span></p>
<p class="MsoNormal">假设当<span lang="EN-US">n=k</span>时成立。<span lang="EN-US"></span></p>
<p class="MsoNormal">我们让<span lang="EN-US">n=k+1</span>,那么:<span lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US">f</span>(<span lang="EN-US">k+1</span>)<span lang="EN-US">=f</span>(<span lang="EN-US">k</span>)<span lang="EN-US">+ min </span>(<span lang="EN-US">B</span>(<span lang="EN-US">k</span>,<span lang="EN-US">k+1</span>))<span lang="EN-US">+ min </span>(<span lang="EN-US">A</span>(<span lang="EN-US">k+1</span>,<span lang="EN-US">k</span>))<span lang="EN-US">- </span>(<span lang="EN-US">when X=Y</span>)<span lang="EN-US">g</span>(<span lang="EN-US">X</span>,<span lang="EN-US">Y</span>)<span lang="EN-US"></span></p>
<p class="MsoNormal">因为<span lang="EN-US">f</span>(<span lang="EN-US">k</span>)是成立的,这是我们的假设,那么<span lang="EN-US">min </span>(<span lang="EN-US">B</span>(<span lang="EN-US">k</span>,<span lang="EN-US">k+1</span>))和<span lang="EN-US">min </span>(<span lang="EN-US">A</span>(<span lang="EN-US">k+1</span>,<span lang="EN-US">k</span>))会不会按照我们预期的工作呢?我想大家都已经知道了!<span lang="EN-US"></span></p>
<p class="MsoNormal">第四:写代码<span lang="EN-US"></span></p>
<p class="MsoNormal">剩下最不起眼的写代码了,这个留给大家吧!<span lang="EN-US"></span></p>


</div>
<p></p>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值