﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Bill Hsu-随笔分类-Algorithm</title><link>http://www.cppblog.com/billhsu/category/7691.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 23 Jun 2011 13:22:13 GMT</lastBuildDate><pubDate>Thu, 23 Jun 2011 13:22:13 GMT</pubDate><ttl>60</ttl><item><title>骨骼动画中的反向动力学</title><link>http://www.cppblog.com/billhsu/archive/2010/08/26/124852.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Thu, 26 Aug 2010 09:29:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2010/08/26/124852.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/124852.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2010/08/26/124852.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/124852.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/124852.html</trackback:ping><description><![CDATA[<span class="Apple-style-span" style="border-collapse: separate; color: #000000; font-family: Simsun; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;">IK在骨骼动画里常常能看到，作用就是根据子骨骼的方位推算出它的那些父骨骼方位。可是一直都是知道有那么回事，但是又不太知道具体是怎么实现的。<br />在multi-crash.com上看到一篇<a target="_blank" href="http://multi-crash.com/?p=45"><span style="font-style: italic;">骨骼动画反向动力学(IK)的实现&nbsp; </span></a>，内容写的很易懂。<br />这是基于CCD(</span>Cyclic Coordinate Descent<span class="Apple-style-span" style="border-collapse: separate; color: #000000; font-family: Simsun; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;">)算法的。还有种雅可比矩阵的算法，不过这种算法我还不太清楚，希望高手指教啊。<br />下面讲讲CCD，先看这张图。<br /><img style="width: 540px; height: 214px;" src="http://www.cppblog.com/images/cppblog_com/billhsu/ccd.gif" border="0"  alt="" /><br />注意图中的红线和绿线，红线是当前骨骼与目标骨骼的连线，绿线是目标骨骼与最终位置的连线。<br />从子骨骼到父骨骼的顺序迭代计算，旋转红线到绿线。这样多迭代几次就会得到较好的结果。<br /><br />要注意的是需要对骨骼的旋转范围加以限制，因为人体的关节不是以可以任意方式旋转的。<br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/ccd3.JPG" border="0"  alt="" /><br />[例如图中蓝色部分为可以旋转的范围]<br /><br /><span style="font-style: italic;"></span></span><img src ="http://www.cppblog.com/billhsu/aggbug/124852.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2010-08-26 17:29 <a href="http://www.cppblog.com/billhsu/archive/2010/08/26/124852.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于shader的骨骼蒙皮计算</title><link>http://www.cppblog.com/billhsu/archive/2010/04/01/111326.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Thu, 01 Apr 2010 14:10:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2010/04/01/111326.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/111326.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2010/04/01/111326.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/111326.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/111326.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 我的古董显卡很操蛋，好端端的shader，传骨骼矩阵进去，硬是没反应。。<br>寻寻觅觅，找到了 NVIDIA SDK 的example，终于解决了。<br>难道我的显卡不支持BLENDINDICES和BLENDWEIGHT?<br>把BLENDINDICES和BLENDWEIGHT用TEXCOORD[n]表示才正常。。<br>不说废话，直接上代码。&nbsp;&nbsp;<a href='http://www.cppblog.com/billhsu/archive/2010/04/01/111326.html'>阅读全文</a><img src ="http://www.cppblog.com/billhsu/aggbug/111326.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2010-04-01 22:10 <a href="http://www.cppblog.com/billhsu/archive/2010/04/01/111326.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GPU水面模拟</title><link>http://www.cppblog.com/billhsu/archive/2010/03/23/110376.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Tue, 23 Mar 2010 12:59:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2010/03/23/110376.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/110376.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2010/03/23/110376.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/110376.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/110376.html</trackback:ping><description><![CDATA[先上个自己实现的水面模拟图：<br /><img id="ViewPicture1_GalleryImage" src="http://www.cppblog.com/images/cppblog_com/billhsu/7643/r_water1.JPG" style="border: 2px solid Black;" height="206" width="274" /><br /><br />效果比较简单，只是模拟了下水面的反射效果。折射与Fresnel系数没有考虑。<br /><br />水面模拟大致需要分这么几步：<br />1.剪裁掉水面以下的顶点[gpu里的clipplane要注意转换到Clip Space]，<br />将摄像机放到同原摄像机关于水面对称的位置，比如原来摄像机在(x,y,z)，<br />此时就该把摄像机放在(x,-y,z)，up向量也要设置成向下的。<br />再把场景渲染到Render Target的纹理上(我用的纹理大小是256*256)，不知道为什么Render Target的纹理大小不能超过窗口大小，超过的话渲染会出错，知道的大大告诉我一下哈。<br /><br />于是，就得到了这样一个纹理：<br /><img id="ViewPicture1_GalleryImage" src="http://www.cppblog.com/images/cppblog_com/billhsu/7643/r_water3.JPG" style="border: 2px solid Black;" height="198" width="198" /><br /><br />2.将上面得到的纹理与水面的顶点对应.<br />把Vertex Shader中乘过变换矩阵后的坐标传到Pixel Shader,<br />在PS中计算<br /><div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">        float2 clipspace = input.Coord.xy / input.Coord.w;<br />        clipspace.x=((clipspace.x * 0.5f) + 0.5f);<br />        clipspace.y = ((clipspace.y * -0.5f) + 0.5f);<br />        clipspace.x=1-clipspace.x;</span><span style="color: rgb(0, 0, 0);"></span></div>既可以让水面顶点与纹理对应，然后再想办法把纹理坐标扰乱来模拟水面波动。<br /><br />3.再渲染一次场景就可以了。<br /><br />大家也可以参考下Azure的水面渲染源代码：<a temp_href=" http://www.azure.com.cn/article.asp?id=186" href="%20http://www.azure.com.cn/article.asp?id=186"><br />http://www.azure.com.cn/article.asp?id=186</a><br /><img src ="http://www.cppblog.com/billhsu/aggbug/110376.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2010-03-23 20:59 <a href="http://www.cppblog.com/billhsu/archive/2010/03/23/110376.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>可编程管道下的剪裁平面</title><link>http://www.cppblog.com/billhsu/archive/2010/01/20/106088.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Wed, 20 Jan 2010 14:00:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2010/01/20/106088.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/106088.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2010/01/20/106088.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/106088.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/106088.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal">
				<span>剪裁平面</span>
				<span>(Clip Plane)</span>
				<span>在图形学领域有着重要的作用，比如水面模拟中，渲染折射纹理时，我们就必须将水面以上的顶点通过剪裁平面剪裁掉。</span>
		</p>
		<p class="MsoNormal">
				<span>在过去的固定渲染管道时代，剪裁平面的实现较为简单，比如在</span>
				<span>DirectX 9</span>
				<span>中，可以先设定剪裁平面在世界坐标系下的方程</span>
				<span>(ax+by+cz+d=0)</span>
				<span>，再调用</span>
				<span>SetClipPlane(DWORD Index,CONST float * pPlane)</span>
				<span>这个</span>
				<span>API</span>
				<span>函数就可以了。</span>
		</p>
		<p class="MsoNormal">
				<span> </span>
		</p>
		<p class="MsoNormal">
				<span>附上例子程序：</span>
		</p>
		<p class="MsoNormal" style="background: none repeat scroll 0% 0% rgb(238, 238, 238); text-align: left; -moz-background-inline-policy: continuous;" align="left">
				<span style="font-size: 10pt; color: black;">vPosition=D3DXVECTOR3(0,0,0);</span>
				<span style="font-size: 10pt; color: green;">//</span>
				<span style="font-size: 10pt; color: green;">平面上一个点<span><br /></span></span>
				<span style="font-size: 10pt; color: black;">vNormal=D3DXVECTOR3(0,1,0);</span>
				<span style="font-size: 10pt; color: green;">//</span>
				<span style="font-size: 10pt; color: green;">法向量<span><br /></span></span>
				<span style="font-size: 10pt; color: black;">D3DXPlaneFromPointNormal( &amp;clipplane, &amp;vPosition, &amp;vNormal );</span>
				<span style="font-size: 10pt; color: green;">//</span>
				<span style="font-size: 10pt; color: green;">生成剪裁平面<span><br /></span></span>
				<span style="font-size: 10pt; color: black;">
						<br />
m_pDevice()-&gt;SetClipPlane( 0, (</span>
				<span style="font-size: 10pt; color: blue;">float</span>
				<span style="font-size: 10pt; color: black;">*)clipplane); </span>
		</p>
		<p class="MsoNormal">
				<span> </span>
		</p>
		<p class="MsoNormal">
				<span>然而，在现在的可编程管道</span>
				<span>(programmable pipeline)</span>
				<span>下，设置的剪裁平面会被在剪裁坐标系下处理，而不是在世界坐标系下。</span>
		</p>
解决这个问题的方法有：<br /><br />
1）  给要剪裁的顶点做标记，在Pixel Shader中把它剪裁掉。<br /><br />
2）  使用近斜平面裁剪（Oblique Near-Plane Clipping），即修改投影矩阵，将要剪裁的顶点放在视截体之外，从而避免了该顶点的绘制。<br /><br />
3）  修改平面方程，使之从世界坐标系转换到剪裁坐标系。<span><br /><br /><br />
上述方法中，第一种和第二种效率并不高：在</span><span>Pixel Shader</span><span>中剪裁没有减少任何不必要的顶点处理，而计算近斜平面裁剪矩阵较为繁琐。所以，方法三是最佳选择。</span><p class="MsoNormal"><span> </span><span>要将一个平面从世界坐标系转换到剪裁坐标系，必须求出这个变换矩阵。</span></p><p class="MsoNormal"><span>设平面方程</span><span>ax+by+cz+d=0</span><span>，用一个</span><span>4</span><span>维向量来</span><span>n</span><span>表示</span><span>(a,b,c,d)</span><span>，设平面上有个点</span><span>p:(x,y,z,1)</span><span>。根据平面方程的定义，有：</span></p><p class="MsoNormal"><span><br /></span></p><p class="MsoNormal"><strong>n</strong><sup>T</sup><strong>p</strong> = ax + by + cz + d = 0</p><p class="MsoNormal"></p><p class="MsoNormal"><span>设矩阵</span><span>R</span><span>可以让点</span><span>P</span><span>从世界坐标系转换到剪裁坐标系，矩阵</span><span>Q</span><span>可以让平面</span><span>n</span><span>实现同样的变换。那么，有：</span></p><p class="MsoNormal" style="text-align: center;" align="center"></p><div align="left"><strong>p</strong>'= <strong>R</strong><strong>p</strong></div><div align="left"><strong>n'</strong>= <strong>Q</strong><strong>n</strong></div><p class="MsoNormal"><span>其中</span><span>p'</span><span>、</span><span>n'</span><span>分别是转换后的点与平面。</span></p><br /><div align="left"><strong>n</strong><span>'</span><sup>T</sup><strong>p'</strong>= 0</div><div align="left">(<strong>Q</strong><strong>n</strong>)<sup>T</sup> (<strong>R</strong><strong>p</strong>) = 0 <br /><strong>n</strong><sup>T</sup><strong>Q</strong><sup>T</sup><strong>R</strong><strong>p</strong> = 0<br /><br /><br /><span>如果：</span><strong>Q</strong><sup>T</sup><strong>R</strong> = <strong>I</strong></div><br /><p class="MsoNormal"><span>那么：</span></p><p class="MsoNormal"><strong>n</strong><sup>T</sup><strong>Q</strong><sup>T</sup><strong>R</strong><strong>p</strong> = <strong>n</strong><sup>T</sup><strong>I</strong><strong>p</strong> = <strong>n</strong><sup>T</sup><strong>p</strong> = 0</p><p class="MsoNormal"><span>于是：</span></p><div align="left"><strong>Q</strong><sup>T</sup> = <strong>R</strong><sup>-1</sup><strong><br />
Q</strong> = (<strong>R</strong><sup>-1</sup>)<sup>T</sup></div><br /><p class="MsoNormal"><span>在</span><span>DirectX 3D</span><span>中，将一个点从世界坐标系转换到剪裁坐标系，所用的矩阵为观察矩阵与投影矩阵的乘积，即：</span></p><p class="MsoNormal" style="background: none repeat scroll 0% 0% rgb(238, 238, 238); -moz-background-inline-policy: continuous;"><span style="font-size: 10pt; color: black;">D3DXMATRIX  TranMatrix = matView*matProj;</span></p><p class="MsoNormal"><span style="font-size: 9pt;">(TranMatrix</span><span style="font-size: 9pt;">为所求的变换矩阵，<span>matView</span>和<span>matProj</span>分别为</span><span>观察矩阵与投影矩阵</span><span>)</span></p><p class="MsoNormal"><span> </span></p><p class="MsoNormal"><span>附上在</span><span>D3D</span><span>中变换的完整代码：</span></p><p class="MsoNormal" style="background: none repeat scroll 0% 0% rgb(238, 238, 238); text-align: left; -moz-background-inline-policy: continuous;" align="left"><span style="font-size: 10pt; color: black;">D3DXPLANE tempPlane = clipplane;<br />
D3DXPlaneNormalize(&amp;tempPlane, &amp;tempPlane);<br /><br />
D3DXMATRIX  TranMatrix = matView*matProj;<br />
D3DXMatrixInverse(&amp;TranMatrix, NULL, &amp;TranMatrix);<br />
D3DXMatrixTranspose(&amp;TranMatrix, &amp;TranMatrix);<br />
D3DXPlaneTransform(&amp;tempPlane, &amp;tempPlane, &amp;TranMatrix);</span></p><p class="MsoNormal" style="background: none repeat scroll 0% 0% rgb(238, 238, 238); text-align: left; -moz-background-inline-policy: continuous;" align="left"></p><p class="MsoNormal"></p><p class="MsoNormal"><span>参考资料：</span></p><p class="MsoNormal"><span>1.Back Face Culling Notes ,Jordan Smith (University of California, Berkeley)<br /></span></p><p class="MsoNormal"><span>http://www.cs.berkeley.edu/~ug/slide/pipeline/assignments/backfacecull.shtml</span> </p><p class="MsoNormal">2.GameDev Forum</p><p class="MsoNormal">http://www.gamedev.net/community/forums/topic.asp?topic_id=402381</p><p class="MsoNormal">3.Oblique Near-Plane Clipping with Orthographic Camera ,Aras</p><p class="MsoNormal">http://aras-p.info/texts/obliqueortho.html</p><img src ="http://www.cppblog.com/billhsu/aggbug/106088.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2010-01-20 22:00 <a href="http://www.cppblog.com/billhsu/archive/2010/01/20/106088.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>矩阵求逆代码</title><link>http://www.cppblog.com/billhsu/archive/2009/12/11/103010.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Fri, 11 Dec 2009 14:23:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2009/12/11/103010.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/103010.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2009/12/11/103010.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/103010.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/103010.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 感觉线性代数作业里一直少不了矩阵求逆，<br><br>写个带输出算逆矩阵的步骤的矩阵求逆程序，希望给即将或正在学线代的同学一点方便。&nbsp;&nbsp;<a href='http://www.cppblog.com/billhsu/archive/2009/12/11/103010.html'>阅读全文</a><img src ="http://www.cppblog.com/billhsu/aggbug/103010.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2009-12-11 22:23 <a href="http://www.cppblog.com/billhsu/archive/2009/12/11/103010.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最酷的排序算法演示</title><link>http://www.cppblog.com/billhsu/archive/2009/11/08/100381.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Sat, 07 Nov 2009 16:08:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2009/11/08/100381.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/100381.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2009/11/08/100381.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/100381.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/100381.html</trackback:ping><description><![CDATA[真的很形象啊( ⊙ o ⊙ )！<br /><div id="blog_text" class="cnt"><embed pluginspage="http://www.macromedia.com/go/getflashplayer" src="http://www.tudou.com/v/htKY1-Rj9ZE" wmode="window" play="true" loop="false" menu="false" width="450" height="390"></embed></div><img src ="http://www.cppblog.com/billhsu/aggbug/100381.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2009-11-08 00:08 <a href="http://www.cppblog.com/billhsu/archive/2009/11/08/100381.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>寻路算法整理</title><link>http://www.cppblog.com/billhsu/archive/2009/01/23/72513.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Fri, 23 Jan 2009 09:22:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2009/01/23/72513.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/72513.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2009/01/23/72513.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/72513.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/72513.html</trackback:ping><description><![CDATA[整理自《Programming Game AI by example》<br /><br />1.DFS<br />优先深入每个图，直到找到目标节点<br />往往可以找到到达路线，可往往不是最优的。<br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/09-1-23-DFS.JPG" alt="09-1-23-DFS.JPG" border="0" width="503" height="551" /><br /><br /><br />2.BFS<br />广度优先地寻找目标节点。<br />往往可以找到最优路径，但耗时多。<br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/09-1-23-BFS.JPG" alt="09-1-23-BFS.JPG" border="0" width="503" height="551" /><br /><br /><br />3.Dijkstra<br />使用了动态规划（原文中称为“边放松”）//该为贪心，本人罪过<br />速度较快<br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/09-1-23-Dijkstra.JPG" alt="09-1-23-Dijkstra.JPG" border="0" width="503" height="551" /><br /><br /><br />4.A*<br />与Dijkstra相似，使用启发因子(F=G+H)，速度是以上算法里最快的。<br />可以看看：<br /><a temp_href="http://hi.baidu.com/probill/blog/item/80d71f1b19e2fe1e8718bfe5.html " href="http://hi.baidu.com/probill/blog/item/80d71f1b19e2fe1e8718bfe5.html%20">http://hi.baidu.com/probill/blog/item/80d71f1b19e2fe1e8718bfe5.html</a><br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/09-1-23-Astar.JPG" alt="09-1-23-Astar.JPG" border="0" width="503" height="551" /><br /><br />5.创建导航图<br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/09-1-23-Nav.JPG" alt="09-1-23-Nav.JPG" border="0" width="480" height="412" /><br /><img src ="http://www.cppblog.com/billhsu/aggbug/72513.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2009-01-23 17:22 <a href="http://www.cppblog.com/billhsu/archive/2009/01/23/72513.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A* (A-star A星)寻路算法</title><link>http://www.cppblog.com/billhsu/archive/2008/11/01/65700.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Sat, 01 Nov 2008 10:19:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2008/11/01/65700.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/65700.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2008/11/01/65700.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/65700.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/65700.html</trackback:ping><description><![CDATA[A*在游戏寻路算法里使用很广，可是感觉很多介绍它的文章故意让人看不懂。<br />仔细看了看gamedev.net的一片文章(<span class="title">A* Pathfinding for Beginners</span>
http://www.gamedev.net/reference/articles/article2003.asp    
          )，对A*更了解了一点，写点东西记录一下。<br />A*是一种启发式的算法，所谓的"启发式"，就是对每一个搜索的位置进行评估，也就是把找的位置离目标的距离当成找点的一个依据，然后猜测这个点是否最佳("启发式"就是猜测)。<br /><br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/image001.jpg" alt="image001.jpg" border="0" width="362" height="256" /><br /><br />为了找到最佳的那个点<br />可以规定：<br />G = 从起点，沿着产生的路径，移动到网格上指定方格的距离。<br />H = 从网格上那个方格移动到终点B的预估移动距离。<br /><br />F = G + H<br />F最小的点可以认为是该选的点。<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">引用</span><span style="color: rgb(0, 0, 0);">一下原文的翻译：<br />我们令水平或者垂直移动的耗费为10，对角线方向耗费为14。我们取这些值是因为沿对角线的距离是沿水平或垂直移动耗费的的根号2（别怕），或者约1.414倍。为了简化，我们用10和14近似。比例基本正确，同时我们避免了求根运算和小数。<br /><br /><br />既然我们在计算沿特定路径通往某个方格的G值，求值的方法就是取它父节点的G值，然后依照它相对父节点是对角线方向或者直角方向(非对角线)，分别增加14和10。例子中这个方法的需求会变得更多，因为我们从起点方格以外获取了不止一个方格。<br /><br />H值可以用不同的方法估算。我们这里使用的方法被称为曼哈顿方法，它计算从当前格到目的格之间水平和垂直的方格的数量总和，忽略对角线方向。然后把结果乘以10。这被成为曼哈顿方法是因为它看起来像计算城市中从一个地方到另外一个地方的街区数，在那里你不能沿对角线方向穿过街区。很重要的一点，我们忽略了一切障碍物。这是对剩余距离的一个估算，而非实际值，这也是这一方法被称为启发式的原因。想知道更多？你可以在这里找到方程和额外的注解。<br /><br /></span></div><br /><br /><span style="color: rgb(0, 0, 0);">第一步搜索的结果可以在下面的图表中看到。F,G和H的评分被写在每个方格里。正如在紧挨起始格右侧的方格所表示的，F被打印在左上角，G在左下角，H则在右下角。</span><br /><br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/image003.jpg" alt="image003.jpg" border="0" width="362" height="255" /><br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">引用</span><span style="color: rgb(0, 0, 0);">一下原文的翻译：</span><br /><span style="color: rgb(0, 0, 0);"><br />我们做如下操作开始搜索：<br />   </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">，从点A开始，并且把它作为待处理点存入一个“开启列表”。开启列表就像一张购物清单。尽管现在列表里只有一个元素，但以后就会多起来。你的路径可能会通过它包含的方格，也可能不会。基本上，这是一个待检查方格的列表。<br />   </span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">，寻找起点周围所有可到达或者可通过的方格，跳过有墙，水，或其他无法通过地形的方格。也把他们加入开启列表。为所有这些方格保存点A作为“父方格”。当我们想描述路径的时候，父方格的资料是十分重要的。后面会解释它的具体用途。<br />   </span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">，从开启列表中删除点A，把它加入到一个“关闭列表”，列表中保存所有不需要再次检查的方格。<br /><br />为了继续搜索，我们简单的从开启列表中选择F值最低的方格。然后，对选中的方格做如下处理：<br /><br />   </span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">，把它从开启列表中删除，然后添加到关闭列表中。<br />   </span><span style="color: rgb(0, 0, 0);">5</span><span style="color: rgb(0, 0, 0);">，检查所有相邻格子。跳过那些已经在关闭列表中的或者不可通过的(有墙，水的地形，或者其他无法通过的地形)，把他们添加进开启列表，如果他们还不在里面的话。把选中的方格作为新的方格的父节点。<br />   </span><span style="color: rgb(0, 0, 0);">6</span><span style="color: rgb(0, 0, 0);">，如果某个相邻格已经在开启列表里了，检查现在的这条路径是否更好。换句话说，检查如果我们用新的路径到达它的话，G值是否会更低一些。如果不是，那就什么都不做。<br />      另一方面，如果新的G值更低，那就把相邻方格的父节点改为目前选中的方格（在上面的图表中，把箭头的方向改为指向这个方格）。最后，重新计算F和G的值。如果这看起来不够清晰，你可以看下面的图示。</span></div><br /><br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/image004.jpg" alt="image004.jpg" border="0" width="357" height="256" /><br /><br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/image005.jpg" alt="image005.jpg" border="0" width="357" height="254" /><br /><br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/image006.jpg" alt="image006.jpg" border="0" width="404" height="307" /><br /><br /><img src="http://www.cppblog.com/images/cppblog_com/billhsu/image007.jpg" alt="image007.jpg" border="0" width="411" height="308" /><br /><br />这样就可以找到最佳路径了。<br /><br /><br /><img src ="http://www.cppblog.com/billhsu/aggbug/65700.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2008-11-01 18:19 <a href="http://www.cppblog.com/billhsu/archive/2008/11/01/65700.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>神经元网络的超级入门</title><link>http://www.cppblog.com/billhsu/archive/2008/08/30/60455.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Sat, 30 Aug 2008 12:08:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2008/08/30/60455.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/60455.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2008/08/30/60455.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/60455.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/60455.html</trackback:ping><description><![CDATA[一直不太懂神经元网络，看了这篇文章(来自IBM developerWorks 中国)后终于感觉有点明白了，特意拿出来大家一起看。<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">2001</span><span style="color: #000000;">&nbsp;年&nbsp;</span><span style="color: #000000;">6</span><span style="color: #000000;">&nbsp;月&nbsp;</span><span style="color: #000000;">01</span><span style="color: #000000;">&nbsp;日<br><br>&nbsp;&nbsp;&nbsp;&nbsp;神经网络也许是计算机计算的将来，一个了解它的好方法是用一个它可以解决的难题来说明。假设给出&nbsp;</span><span style="color: #000000;">500</span><span style="color: #000000;">&nbsp;个字符的代码段，您知道它们是&nbsp;C、C</span><span style="color: #000000;">++</span><span style="color: #000000;">、Java&nbsp;或者&nbsp;Python。现在构造一个程序，来识别编写这段代码的语言。一种解决方案是构造一个能够学习识别这些语言的神经网络。这篇文章讨论了神经网络的基本功能以及构造神经网络的方法，这样就可以在编码时应用它们了。</span></div>
<br>Bill注：解释一下，这文章是用) ( _ . = ; " , ' * / { } : - 0 + 1 [ ] 这20个特殊符号出现频率+人工神经元的判断来识别<span style="color: #000000;">代码段</span><span style="color: #000000;">是&nbsp;C、C</span><span style="color: #000000;">++</span><span style="color: #000000;">、Java&nbsp;或者&nbsp;Python<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;"></span><br>
<p>根据一个简化的统计，人脑由百亿条神经组成 ―
每条神经平均连结到其它几千条神经。通过这种连结方式，神经可以收发不同数量的能量。神经的一个非常重要的功能是它们对能量的接受并不是立即作出响应，而
是将它们累加起来，当这个累加的总和达到某个临界阈值时，它们将它们自己的那部分能量发送给其它的神经。大脑通过调节这些连结的数目和强度进行学习。尽管
这是个生物行为的简化描述。但同样可以充分有力地被看作是神经网络的模型。</p>
<p><a name="1"><span class="atitle">阈值逻辑单元（Threshold Logic
Unit，TLU）</span></a></p>
<p>
理解神经网络的第一步是从对抽象生物神经开始，并把重点放在
<em>阈值逻辑单元（TLU）</em>这一特征上。一个
TLU
是一个对象，它可以输入一组加权系数的量，对它们进行求和，如果这个和达到或者超过了某个阈值，输出一个量。
让我们用符号标注这些功能，首先，有输入值以及它们的权系数：X
<sub>1</sub>,
X
<sub>2</sub>, ..., X
<sub>n</sub>和 W
<sub>1</sub>, W
<sub>2,</sub>
..., W
<sub>n</sub>。接着是求和计算出的 X
<sub>i</sub>*W
<sub>i</sub>
，产生了激发层 a，换一种方法表示：
</p>
<p>a = (X1 * W1)+(X2 * W2)+...+(Xi * Wi)+...+ (Xn * Wn)</p>
<p>阈值称为 theta。最后，输出结果 y。当 a &gt;=theta 时 y=1，反之
y=0。请注意输出可以是连续的，因为它也可以由一个 squash 函数 s（或
sigma）判定，该函数的自变量是 a，函数值在 0 和 1 之间，y=s(a)。</p>
<br><a name="N10080"><strong>图 1. 阈值逻辑单元，带有 sigma 函数（顶部）和 cutoff
函数（底部）
</strong></a><br>
<img src="http://www.ibm.com/developerworks/cn/linux/other/l-neural/mp.gif" alt="阈值逻辑单元" width="300" height="275">
<br>
<p>TLU 会分类，假设一个 TLU 有两个输入值，它们的权系数等于 1，theta
值等于 1.5。当这个 TLU 输入 &lt;0,0&gt;、&lt;0,1&gt;、&lt;1,0&gt;
和 &lt;1,1&gt; 时，它的输出分别为 0、0、0、1。TLU
将这些输入分为两组：0 组和 1 组。就像懂得逻辑连接（布尔运算
AND）的人脑可以类似地将逻辑连接的句子分类那样，TLU
也懂得一点逻辑连接之类的东西。</p>
<p>TLU
能够用几何学上的解释来阐明这种现象。它的四种可能输入对应于笛卡尔图的四个点。从等式
X
<sub>1</sub>*W
<sub>1</sub>+ X
<sub>2</sub>*W
<sub>2</sub> =
theta，换句话说，也即 TLU
转换其分类行为的点开始，它的点都分布在曲线 X
<sub>2</sub> =
-X
<sub>1</sub> + 1.5 上。这个方程的曲线将 4
个可能的输入分成了两个对应于 TLU 分类的区域。这是 TLU
原理中更为普通的实例。在 TLU 有任意数目的 N
个输入的情况下，一组可能的输入对应于 N
维空间中的一个点集。如果这些点可以被超平面 ―
换句话说，对应于上面示例中的线的 N
维的几何外形切割，那么就有一组权系数和一个阈值来定义其分类刚好与这个切割相匹配的
TLU。
</p>
</div>
</span>Bill注：<span style="color: #000000;">所谓的</span><span style="color: #000000;">N维空间就是N个输入节点<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;"> </span><br>
<p><a name="2"><span class="atitle">TLU
的学习原理</span></a></p>
<p>
既然 TLU
懂得分类，它们就知道素材。神经网络也可假定为可以学习。它们的学习机制是模仿大脑调节神经连结的原理。TLU
通过改变它的权系数和阈值来学习。实际上，从数学的观点看，权系数阈值的特征有点武断。让我们回想一下当
SUM(Xi * Wi) &gt;= theta 时 TLU 在临界点时输出的是 1 而不是
0，这相当于说临界点是出现在 SUM(X
<sub>i</sub>* W
<sub>i</sub>)+ (-1
* theta) &gt;= 0 的时候。所以，我们可以把 -1
看成一个常量输入，它的权系数 theta
在学习（或者用技术术语，称为
<em>培训</em>）的过程中进行调整。这样，当
SUM(X
<sub>i</sub>* W
<sub>i</sub>)+ (-1 * theta) &gt;= 0
时，y=1，反之 y=0。
</p>
<p>在培训过程中，神经网络输入：</p>
<ol>
    <li>一系列需要分类的术语示例</li>
    <li>它们的正确分类或者目标</li>
</ol>
<p>这样的输入可以看成一个向量：&lt;X
<sub>1</sub>, X
<sub>2</sub>,
..., X
<sub>n</sub>, theta, t&gt;，这里 t
是一个目标或者正确分类。神经网络用这些来调整权系数，其目的使培训中的目标与其分类相匹配。更确切地说，这是有指导的培训，与之相反的是无指导的培训。前者是基于带目标的示例，而后者却只是建立在统计分析的基础上。权系数的调整有一个学习规则，一个理想化的学习算法如下所示：
</p>
<br><a name="listing1"><strong>清单 1.
理想化的学习算法</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">fully_trained = FALSE<br>DO UNTIL (fully_trained):<br>    fully_trained = TRUE<br>    FOR EACH training_vector = &lt;X1, X2, ..., Xn, theta, target&gt;::<br>                               # Weights compared to theta<br>        a = (X1 * W1)+(X2 * W2)+...+(Xn * Wn) - theta<br>        y = sigma(a)<br>        IF y != target:<br>            fully_trained = FALSE<br>        FOR EACH Wi:<br>        MODIFY_WEIGHT(Wi)      # According to the training rule<br>    IF (fully_trained):<br>        BREAK<br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>
您或许想知道，&#8220;哪些培训规则？&#8221;有很多，不过有一条似乎合理的规则是基于这样一种思想，即权系数和阈值的调整应该由分式
(t - y) 确定。这个规则通过引入 alpha (0 &lt; alpha &lt; 1)
完成。我们把 alpha 称为
<em>学习率</em>。W
<sub>i</sub> 中的更改值等于
(alpha * (t - y)* Xi)。当 alpha 趋向于 0
时，神经网络的权系数的调整变得保守一点；当 alpha 趋向于 1
时，权系数的调整变得激进。一个使用这个规则的神经网络称为
<em>感知器</em>，并且这个规则被称为
<em>
感知器学习规则</em>。Rosenblatt 于 1962 年下的结论是，如果 N
维空间的点集被超平面切割，那么感知器的培训算法的应用将会最终导致权系数的分配，从而定义了一个
TLU，它的超平面会进行需要的分割。当然，为了记起
Keynes，最终我们都切断了与外界的联系，专心思考。但是在计算时间之外，我们仍濒临危险，因为我们需要自己的神经网络对可能输入的空间进行不止一次的切割。
</p>
<p>文章开始的难题举例说明了这个，假设给您 N
个字符的代码段，您知道是 C、C++、Java 或者
Python。难的是构造一个程序来标识编写这段代码的语言。用 TLU
来实现需要对可能的输入空间进行不止一次的分割。它需要把空间分成四个区域。每种语言一个区域。把神经网络培训成能实现两个切割就可完成这种工作。第一个切割将
C/C++ 和 Java/Python 分开来，另一个将 C/Java 和 C++/Python
分开。一个能够完成这些切割的网络同样可以识别源代码样本中的语言。但是这需要网络有不同结构，在描述这个不同之处之前，先来简单地看一下实践方面的考虑。</p>
<p>
<strong>图 2. 初步的（不完整的）感知器学习模型</strong>
<br>
<a href="http://www.ibm.com/developerworks/cn/linux/other/l-neural/lr.gif">
<img src="http://www.ibm.com/developerworks/cn/linux/other/l-neural/lr.gif" alt="感知器学习模型" name="Graphic2" border="0" width="430" height="300">
</a>
</p>
<p>考虑到排除取得 N 个字符代码所需的计算时间，统计从 ASCII 码的 32
到 127 的范围内可视 ASCII
码字符出现的频率，并在这个统计以及关于代码语言的目标信息的基础上培训神经网络。我们的方法是将字符统计限制到
C、C++、Java 和 Python 代码字符库中最常用的 20
个非字母数字字符。由于关注浮点运算的执行，我们打算用一种规格化因素将这
20
字符统计分开来，并以此培训我们的网络。显然，一个结构上的不同是我们的网络有
20
个输入节点，但这是很正常的，因为我们的描述已经暗示了这种可能性。一个更有意思的区别是出现了一对中间节点，N1
和 N2，以及输出节点数量从两个变成了四个（O1 到 O4）。</p>
<p>我们将培训 N1，这样当它一看到 C 或 C++，设置 y1=1，看到 Java 或
Python，它将设置 y1=0。同理培训 N2，当它一看到 C 或 Java，设置
y2=1，看到 C++ 或 Python，设置 y2=0。此外，N1 和 N2 将输出 1 或 0
给 Oi。现在如果 N1 看到 C 或 C++，而且 N2 看到 C 或者
Java，那么难题中的代码是 C。而如果 N1 看到 C 或 C++，N2 看到 C++ 或
Python，那么代码就是 C++。这个模式很显而易见。所以假设 Oi
已被培训并根据下面表格的情况输出 1 或 0。</p>
<p><a name="listing2"><span class="smalltitle">映射到输出（作为布尔函数）的中间节点</span></a></p>
<p>
</p>
<table border="1" cellpadding="4" cellspacing="0">
    <tbody>
        <tr valign="top">
            <td bgcolor="#cccccc" width="17%">
            N1
            </td>
            <td bgcolor="#cccccc" width="17%">
            N2
            </td>
            <td bgcolor="#cccccc" width="17%">
            O1 (C)
            </td>
            <td bgcolor="#cccccc" width="17%">
            O2 (C++)
            </td>
            <td bgcolor="#cccccc" width="17%">
            O3 (Java)
            </td>
            <td bgcolor="#cccccc" width="17%">
            O4 (Python)
            </td>
        </tr>
        <tr valign="bottom">
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            1
            </td>
        </tr>
        <tr valign="bottom">
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            1
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            1
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
        </tr>
        <tr valign="bottom">
            <td bgcolor="#cccccc" width="17%">
            1
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            1
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
        </tr>
        <tr valign="bottom">
            <td bgcolor="#cccccc" width="17%">
            1
            </td>
            <td bgcolor="#cccccc" width="17%">
            1
            </td>
            <td bgcolor="#cccccc" width="17%">
            1
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
            <td bgcolor="#cccccc" width="17%">
            0
            </td>
        </tr>
    </tbody>
</table>
<p>
如果这样可行的话，我们的网络就可以从代码示例中识别出语言了。这个想法很好。但是在实践上却有些难以置信。不过这种解决方案预示了
C/C++ 和 Java/Python 输入被一个超平面切割了，同样 C/Java 和
C++/Python
输入被另一个切割。这是一个网络培训的解决方案，迂回地解决了这个输入空间的设想。</p>
</div>
</span>Bill注：看起来很强大<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;"> <br></span>
<p><a name="3"><span class="atitle">关于 delta
规则</span></a></p>
<p>
另一种培训的规则叫做 delta 规则。感知器培训规则是基于这样一种思路
― 权系数的调整是由目标和输出的差分方程表达式决定。而
<em>delta</em>
规则是基于梯度降落这样一种思路。这个复杂的数学概念可以举个简单的例子来表示。从给定的几点来看，向南的那条路径比向东那条更陡些。向东就像从悬崖上掉
下来，但是向南就是沿着一个略微倾斜的斜坡下来，向西像登一座陡峭的山，而北边则到了平地，只要慢慢的闲逛就可以了。所以您要寻找的是到达平地的所有路径
中将陡峭的总和减少到最小的路径。在权系数的调整中，神经网络将会找到一种将误差减少到最小的权系数的分配方式。 </p>
<p>
将我们的网络限制为没有隐藏节点，但是可能会有不止一个的输出节点，设
p 是一组培训中的一个元素，t(p,n) 是相应的输出节点 n
的目标。但是，设 y(p,n) 由以上提到的 squash 函数 s 决定，这里
a(p,n) 是与 p 相关的 n 的激活函数，或者用 (p,n) = s( a(p,n) )
表示为与 p 相关的节点 n 的 squash
过的激活函数。为网络设定权系数（每个 Wi），也为每个 p 和 n 建立
t(p,n) 与 y(p,n) 的差分，这就意味着为每个 p
设定了网络全部的误差。因此对于每组权系数来说有一个平均误差。但是
delta
规则取决于求平均值方法的精确度以及误差。我们先不讨论细节问题，只是说一些与某些
p 和 n 相关的误差：?* square( t(p,n) - y(p,n) )。现在，对于每个
Wi，平均误差定义如下：
</p>
<br><a name="listing3"><strong>清单 2.
查找平均误差</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">sum = 0<br>FOR p = 1 TO M:         # M is number of training vectors<br>    FOR n = 1 TO N:     # N is number of output nodes<br>        sum = sum + (1/2 * (t(p,n)-y(p,n))^2)<br>average = 1/M * sum<br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>delta
规则就是依据这个误差的定义来定义的。因为误差是依据那些培训向量来说明的，delta
规则是一种获取一个特殊的权系数集以及一个特殊的向量的算法。而改变权系数将会使神经网络的误差最小化。我们不需要讨论支持这个算法的微积分学，只要认为任何
Wi 发生的变化都是如下所示就够了：</p>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">alpha * s'(a(p,n)) * (t(p,n) - y(p,n)) * X(p,i,n).<br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>X(p,i,n) 是输入到节点 n 的 p 中的第 i 个元素，alpha
是已知的学习率。最后 s'( a(p,n) ) 是与 p 相关的第 n 个节点激活的
squashing 函数的变化（派生）率，这就是 delta 规则，并且 Widrow 和
Stearns 向我们展示了当
alpha
非常小的时候，权系数向量接近某个将误差最小化的向量。用于权系数调节的基于
delta 规则的算法就是如此。
</p>
<br><a name="listing4"><strong>梯度降落（直到误差小到适当的程度为止）</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">step 1: for each training vector, p, find a(p)<br>step 2: for each i, change Wi by:<br>            alpha * s'(a(p,n)) * (t(p,n)-y(p,n)) * X(p,i,n)<br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>
这里有一些与感知器算法相区别的重要不同点。显然，在权系数调整的公式下有着完全不同的分析。delta
规则算法总是在权系数上调整，而且这是建立在相对输出的激活方式上。最后，这不一定适用于存在隐藏节点的网络。</p>
<p>
<em>反向传播</em>这一算法把支持 delta
规则的分析扩展到了带有隐藏节点的神经网络。为了理解这个问题，设想
Bob 给 Alice 讲了一个故事，然后 Alice 又讲给了 Ted，Ted
检查了这个事实真相，发现这个故事是错误的。现在 Ted
需要找出哪些错误是 Bob 造成的而哪些又归咎于
Alice。当输出节点从隐藏节点获得输入，网络发现出现了误差，权系数的调整需要一个算法来找出整个误差是由多少不同的节点造成的，网络需要问，&#8220;是谁让我误入歧途？到怎样的程度？如何弥补？&#8221;这时，网络该怎么做呢？
</p>
<br><a name="N10215"><strong>图 3：&#8220;代码识别&#8221;反向传播的神经网络
</strong></a><br>
<img src="http://www.ibm.com/developerworks/cn/linux/other/l-neural/code_recognizer.gif" alt="" width="464" height="437">
<br>
<p>
反向传播算法同样来源于梯度降落原理，在权系数调整分析中的唯一不同是涉及到
t(p,n) 与 y(p,n) 的差分。通常来说 W
<sub>i</sub>的改变在于：
</p>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">alpha * s'(a(p,n)) * d(n) * X(p,i,n)</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>其中 d(n) 是隐藏节点 n 的函数，让我们来看（1）n
对任何给出的输出节点有多大影响；（2）输出节点本身对网络整体的误差有多少影响。一方面，n
影响一个输出节点越多，n
造成网络整体的误差也越多。另一方面，如果输出节点影响网络整体的误差越少，n
对输出节点的影响也相应减少。这里 d(j)
是对网络的整体误差的基值，W(n,j) 是 n 对 j 造成的影响，d(j) *
W(n,j) 是这两种影响的总和。但是 n
几乎总是影响多个输出节点，也许会影响每一个输出结点，这样，d(n)
可以表示为：</p>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">SUM(d(j)*W(n,j))</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>这里 j 是一个从 n
获得输入的输出节点，联系起来，我们就得到了一个培训规则，第 1
部分：在隐藏节点 n 和输出节点 j 之间权系数改变，如下所示：</p>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">alpha * s'(a(p,n))*(t(p,n) - y(p,n)) * X(p,n,j)</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>第 2 部分：在输入节点 i 和输出节点 n
之间权系数改变，如下所示：</p>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">alpha * s'(a(p,n)) * sum(d(j) * W(n,j)) * X(p,i,n)</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>这里每个从 n 接收输入的输出节点 j
都不同。关于反向传播算法的基本情况大致如此。</p>
<p>将 Wi 初始化为小的随机值。</p>
<p><a name="listing5"><span class="smalltitle">使误差小到适当的程度要遵循的步骤</span></a></p>
<p>
</p>
<table border="1" cellpadding="5" cellspacing="0" width="60%">
    <tbody>
        <tr>
            <td>第 1
            步：输入培训向量。
            <br>
            第 2 步：隐藏节点计算它们的输出
            <br>
            第 3 步：输出节点在第 2 步的基础上计算它们的输出。
            <br>
            第 4 步：计算第 3 步所得的结果和期望值之间的差。
            <br>
            第 5 步：把第 4 步的结果填入培训规则的第 1 部分。
            <br>
            第 6 步：对于每个隐藏节点 n，计算 d(n)。
            <br>
            第 7 步：把第 6 步的结果填入培训规则的第 2 部分。
            </td>
        </tr>
    </tbody>
</table>
<p>通常把第 1 步到第 3 步称为
<em>正向传播</em>，把第 4 步到第 7
步称为
<em>反向传播</em>。反向传播的名字由此而来。 <br></p>
<p>
在掌握了反向传播算法后，可以来看我们的识别源代码样本语言的难题。为了解决这个问题，我们提供了
Neil Schemenauer 的 Python 模型
<em>bpnn</em>。用它的模型解决问题真是难以置信的简单，在我们的类
<code>
<em>NN2</em>
</code> 里定制了一个类
<code>
<em>NN</em>
</code> ，不过我们的改变只是调整了表达方式和整个过程的输出，并没有涉及到算法。基本的代码如下所示：
</p>
<br><a name="listing6"><strong>清单 3：用 bpnn.py
建立一个神经网络</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">                # Create the network (number of input, hidden, and training nodes)<br>net = NN2(INPUTS, HIDDEN, OUTPUTS) <br>        # create the training and testing data<br>trainpat = []  <br>testpat = []  <br>for n in xrange(TRAINSIZE+TESTSIZE):  <br>    <br>        #... add vectors to each set<br># train it with some patterns <br>net.train(trainpat, iterations=ITERATIONS, N=LEARNRATE, M=MOMENTUM)  <br>        # test it <br>net.test(testpat)  <br>        # report trained weights <br>net.weights()<br>			<br>      </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>当然我们需要输入数据，实用程序 code2data.py
提供了这个功能。它的界面很直观：只要将一堆扩展名各不相同的文件放到一个子目录
./code
中，然后运行这个实用程序，并列举那些扩展名作为命令选项。例如：</p>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">python code2data.py py c java</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>您得到的是一堆 STDOUT
上的向量，可以把这些向量输入到另一个进程或者重定向到一个文件，它的输出如下所示：</p>
<br><a name="listing7"><strong>清单 4：Code2Data
的输出向量</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">0.15 0.01 0.01 0.04 0.07 0.00 0.00 0.03 0.01 0.00 0.00 0.00 0.05 0.00 &gt; 1 0 0<br>0.14 0.00 0.00 0.05 0.13 0.00 0.00 0.00 0.02 0.00 0.00 0.00 0.13 0.00 &gt; 1 0 0<br>[...]</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>
让我们回忆一下输入值都是不同特殊字符出现的规格化数目，目标值（在大于号以后）是
YES/NO，它代表包含这些字符的源代码文件的类型，不过对于什么是什么来说，并没有非常明显的东西。数字可以是输入或期望的
<em>
任意值</em>，这才是最重要的。
</p>
<p>下一步是运行实际的 code_recognizer.py 程序。这需要（在
STDIN
中）像上面一样的向量集。这个程序有一个包，它能够根据实际文件推断出需要多少输入节点（计算在内的和期望的），选择隐藏节点的数目是一个诀窍。对于源代码的识别，6
到 8
个隐藏节点似乎工作得很好。如果打算试验网络从而发现对于这些不同的选项它是如何做的，您可以覆盖命令行中的所有参数，但每一次运行还是会耗费一些时间。值得注意的是，
code_recognizer.py 将它的（大的）测试结果文件发送到
STDOUT，而将一些友好的消息放在 STDERR
里。这样在大部分时间里，为了安全保管，您将会把 STDOUT
定向到一个文件，并监视针对进程和结果概要的 STDERR。</p>
<br><a name="listing8"><strong>清单 5：运行
code_recognizer.py</strong></a><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">&gt; code2data.py py c java | code_recognizer.py &gt; test_results.txt <br>Total bytes of py-source: 457729 <br>Total bytes of c-source: 245197 <br>Total bytes of java-source: 709858 <br>Input set: ) ( _ . = ; " , ' * / { } : - 0 + 1 [ ] <br>HIDDEN = 8 <br>LEARNRATE = 0.5 <br>ITERATIONS = 1000 <br>TRAINSIZE = 500 <br>OUTPUTS = 3 <br>MOMENTUM = 0.1 <br>ERROR_CUTOFF = 0.01 <br>TESTSIZE = 500 <br>INPUTS = 20 <br>error -&gt; 95.519... 23.696... 19.727... 14.012... 11.058... 9.652...  <br>8.858... 8.236... 7.637... 7.065... 6.398... 5.413... 4.508...  <br>3.860... 3.523... 3.258... 3.026... 2.818... 2.631... 2.463...  <br>2.313... 2.180... 2.065... 1.965... 1.877... 1.798... 1.725...  <br>[...] <br>0.113... 0.110... 0.108... 0.106... 0.104... 0.102... 0.100...  <br>0.098... 0.096... 0.094... 0.093... 0.091... 0.089... 0.088...  <br>0.086... 0.085... 0.084... <br>Success rate against test data: 92.60% <br></pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>
不断减少误差是个很好的兆头，这至少在一段长时间里所获得的一种进步，且最后的结果必然是深入人心的。就我们的观点而言，网络完成了一项值得尊敬的工作，来识别代码
― 我们将会乐意倾听，对于您的数字向量它是如何做的。
</p>
</div>
<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><br>
<p><a name="resources"><span class="atitle">参考资料 </span></a></p>
<ul>
    <li>您可以参阅本文在 developerWorks 全球站点上的
    <a href="http://www.ibm.com/developerworks/library/l-neural/index.html?S_TACT=105AGX52&amp;S_CMP=cn-a-l">英文原文</a>.
    <br><br></li>
    <li>我们的
    <a href="http://gnosis.cx/download/neural_net_1.zip">代码识别</a>程序是基于
    Neil Schemenauer 的反向传播模块。
    <br><br></li>
    <li>
    关于有指导培训和无指导培训的差异，以及神经网络的一般介绍，请参阅由
    D. Michie、D.J. Spiegelhalter 以及 C.C. Taylor 编辑的
    <a href="http://www.amsta.leeds.ac.uk/%7Echarles/statlog">Machine
    Learning, Neural and Statistical
    Classification</a>，具体内容请参阅
    <a href="http://www.amsta.leeds.ac.uk/%7Echarles/statlog/chap6.ps.gz">第
    6 章</a>。
    <br><br></li>
    <li>关于 Rosenblatt 的感知器结果，请参阅他的
    <em>Principles of
    Neurodynamics</em>, 1962, New York: Spartan Books。
    <br><br></li>
    <li>关于一些 delta 规则的详细信息，请参阅 Kevin Gurney 的著作
    <em>An
    Introduction to Neural Networks</em> 1997, London:
    Routledge。也可以参阅
    <a href="http://www.shef.ac.uk/psychology/gurney/notes/contents.html">Neural
    Nets</a>早期的在线版本。
    <br><br></li>
    <li>关于 delta 规则的证明，请参阅 B. Widrow 和 S.D. Stearns 的
    <em>Adaptive Signal Processing</em>, 1985, New Jersey:
    Prentice-Hall。
    <br><br></li>
    <li>关于包含图形界面的感知器的执行，请参阅 Omri Weisman 和 Ziv
    Pollack 撰写的
    <a href="http://www.cs.bgu.ac.il/%7Eomri/Perceptron/">The Perceptron</a>
    。
    <br><br></li>
    <li>什么是没有 FAQ 的科目？请参阅在任何时候都适用的
    <a href="ftp://ftp.sas.com/pub/neural/FAQ.html">Neural Net
    FAQ</a>。
    <br><br></li>
    <li>关于广泛的链接集合，请参阅
    <a href="http://www.dontveter.com/bpr/bpr.html">The Backpropagator's
    Review</a>。
    <br><br></li>
    <li>请参阅
    <a href="http://www.geocities.com/CapeCanaveral/1624/">Neural Networks
    at your Fingertips</a>，它讨论了一组 C 程序包，这些包说明了 Adaline
    网络、反向传播、Hopfield 模型以及其它，有一个
    <a href="http://www.geocities.com/CapeCanaveral/1624/bpn.html">The
    Back-propagation Network</a> 特别有趣，它是一个 C
    程序包，说明了一个分析日斑数据的网络。
    <br><br></li>
    <li>在
    <a href="http://www.dontveter.com/nnsoft/nnsoft.html">Neural
    Networking Software</a>，您将会找到有友好的图形界面的同时支持 DOS
    和 Linux 的神经网络代码。
    <br><br></li>
    <li>
    <a href="http://www.disi.unige.it/person/ValentiniG/NEURObjects">NEURObjects</a>
    提供了开发神经网络的 C++ 的库文件，它的优点在于面向对象。
    <br><br></li>
    <li>
    <a href="http://www-ra.informatik.uni-tuebingen.de/SNNS/">Stuttgart
    Neural Network Simulator</a>（SNNS），正如名字所示，是用有 GUI 的 C
    程序编写的，它的手册内容极为丰富，同时支持友好的 Linux 平台。
    <br></li>
</ul>
</div>
<br><br> <img src ="http://www.cppblog.com/billhsu/aggbug/60455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2008-08-30 20:08 <a href="http://www.cppblog.com/billhsu/archive/2008/08/30/60455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>stredit problem</title><link>http://www.cppblog.com/billhsu/archive/2008/08/01/57754.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Fri, 01 Aug 2008 05:41:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2008/08/01/57754.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/57754.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2008/08/01/57754.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/57754.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/57754.html</trackback:ping><description><![CDATA[s and t are two strings.<br>Change string s into string t in the least steps.<br>In each step you can insert or delete a char of the string.<br>INPUT n1 s<br>             n2 t<br>n1 is the length of string s<br>n2 is the length of string t<br>OUT  the least steps<br>exp:  <br>INPUT  4 abcd<br>              6 aefbhd<br>OUT  4
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">#include</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">iostream</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>#include</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><br></span><span style="color: #0000ff;">using</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">namespace</span><span style="color: #000000;">&nbsp;std;<br><br></span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;s1,s2;<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;map[</span><span style="color: #000000;">100</span><span style="color: #000000;">];<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i,j,result[</span><span style="color: #000000;">100</span><span style="color: #000000;">];<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;n1,n2,nc;<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;main(){<br>&nbsp;&nbsp;&nbsp;&nbsp;cin</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">n1</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">s1</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">n2</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">s2;<br>&nbsp;&nbsp;&nbsp;&nbsp;nc</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">n1;i</span><span style="color: #000000;">++</span><span style="color: #000000;">){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;((j</span><span style="color: #000000;">=</span><span style="color: #000000;">s2.find(s1[i]))</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">0</span><span style="color: #000000;">){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map[nc]</span><span style="color: #000000;">=</span><span style="color: #000000;">j;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s2.replace(j,</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nc</span><span style="color: #000000;">++</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;result[nc</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">]</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(i</span><span style="color: #000000;">=</span><span style="color: #000000;">nc</span><span style="color: #000000;">-</span><span style="color: #000000;">2</span><span style="color: #000000;">;i</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">0</span><span style="color: #000000;">;i</span><span style="color: #000000;">--</span><span style="color: #000000;">){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(j</span><span style="color: #000000;">=</span><span style="color: #000000;">i</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">;j</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">nc;j</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;((map[i]</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">map[j])</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">(result[i]</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">result[j]))&nbsp;result[i]</span><span style="color: #000000;">=</span><span style="color: #000000;">result[j];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result[i]</span><span style="color: #000000;">++</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;j</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">nc;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(result[i]</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">j)&nbsp;j</span><span style="color: #000000;">=</span><span style="color: #000000;">result[i];<br>&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">n1</span><span style="color: #000000;">+</span><span style="color: #000000;">n2</span><span style="color: #000000;">-</span><span style="color: #000000;">j</span><span style="color: #000000;">-</span><span style="color: #000000;">j;<br>&nbsp;&nbsp;&nbsp;&nbsp;system(</span><span style="color: #000000;">"</span><span style="color: #000000;">pause</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}</span></div>
<br><br><br><img src ="http://www.cppblog.com/billhsu/aggbug/57754.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2008-08-01 13:41 <a href="http://www.cppblog.com/billhsu/archive/2008/08/01/57754.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>石子合并</title><link>http://www.cppblog.com/billhsu/archive/2008/07/24/57083.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Thu, 24 Jul 2008 13:37:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2008/07/24/57083.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/57083.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2008/07/24/57083.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/57083.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/57083.html</trackback:ping><description><![CDATA[附上题目：<br>
在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆，并将新的一堆石子数记为该次合并的得分。试设计一个算法，计算出将n堆石子合并成一堆的最小得分和最大得分。<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008000;">/*</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;Name:&nbsp;Stone&nbsp;Problem<br>&nbsp;&nbsp;&nbsp;Copyleft:&nbsp;www.graptor.com<br>&nbsp;&nbsp;&nbsp;Author:&nbsp;Bill&nbsp;Hsu<br>&nbsp;&nbsp;&nbsp;Date:&nbsp;27-04-08&nbsp;15:15<br></span><span style="color: #008000;">*/</span><span style="color: #000000;"><br><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">iostream</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">fstream</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><br></span><span style="color: #0000ff;">#define</span><span style="color: #000000;">&nbsp;MAX&nbsp;100</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">#define</span><span style="color: #000000;">&nbsp;MAXint&nbsp;1000</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">using</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">namespace</span><span style="color: #000000;">&nbsp;std;<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i,j;</span><span style="color: #008000;">//</span><span style="color: #008000;">循环用的</span><span style="color: #008000;"><br></span><span style="color: #000000;">ifstream&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">(</span><span style="color: #000000;">"</span><span style="color: #000000;">in.txt</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>ofstream&nbsp;</span><span style="color: #0000ff;">out</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">"</span><span style="color: #000000;">out.txt</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;f[MAX][MAX];</span><span style="color: #008000;">//</span><span style="color: #008000;">f[i][j]表示从i起取j堆的最大值</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;sum[MAX][MAX];</span><span style="color: #008000;">//</span><span style="color: #008000;">sum[i][j]表示从i起取j堆的和</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;num[MAX];<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;main()<br>{<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;n;<br></span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">n;<br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">(i</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">;i</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">n;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br>{<br></span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">num[i];<br>sum[i][</span><span style="color: #000000;">1</span><span style="color: #000000;">]</span><span style="color: #000000;">=</span><span style="color: #000000;">num[i];<br>f[i][</span><span style="color: #000000;">1</span><span style="color: #000000;">]</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}</span><span style="color: #008000;">//</span><span style="color: #008000;">end&nbsp;for</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(j</span><span style="color: #000000;">=</span><span style="color: #000000;">2</span><span style="color: #000000;">;j</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">n;</span><span style="color: #000000;">++</span><span style="color: #000000;">j)<br>{<br>cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">endl</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">j</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">endl</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">endl;<br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">(i</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">;i</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">n;</span><span style="color: #000000;">++</span><span style="color: #000000;">i)<br>{<br>cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">(sum[i][j]</span><span style="color: #000000;">=</span><span style="color: #000000;">num[i]</span><span style="color: #000000;">+</span><span style="color: #000000;">sum[i</span><span style="color: #000000;">%</span><span style="color: #000000;">n</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">][j</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">])</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">endl;<br><br>}</span><span style="color: #008000;">//</span><span style="color: #008000;">end&nbsp;for&nbsp;i</span><span style="color: #008000;"><br></span><span style="color: #000000;">}</span><span style="color: #008000;">//</span><span style="color: #008000;">end&nbsp;for&nbsp;j</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;k,x,t;<br><br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(j</span><span style="color: #000000;">=</span><span style="color: #000000;">2</span><span style="color: #000000;">;j</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">n;j</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br>{<br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">(i</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">;i</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">n;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br>{<br>f[i][j]</span><span style="color: #000000;">=</span><span style="color: #000000;">MAXint;<br>t</span><span style="color: #000000;">=</span><span style="color: #000000;">sum[i][j];<br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">(k</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">;k</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">j</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;k</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br>{<br>x</span><span style="color: #000000;">=</span><span style="color: #000000;">(i</span><span style="color: #000000;">+</span><span style="color: #000000;">k</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">%</span><span style="color: #000000;">n</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">(f[i][k]</span><span style="color: #000000;">+</span><span style="color: #000000;">f[x][j</span><span style="color: #000000;">-</span><span style="color: #000000;">k]</span><span style="color: #000000;">+</span><span style="color: #000000;">t</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">f[i][j])<br>f[i][j]</span><span style="color: #000000;">=</span><span style="color: #000000;">f[i][k]</span><span style="color: #000000;">+</span><span style="color: #000000;">f[x][j</span><span style="color: #000000;">-</span><span style="color: #000000;">k]</span><span style="color: #000000;">+</span><span style="color: #000000;">t;<br>}</span><span style="color: #008000;">//</span><span style="color: #008000;">end&nbsp;for&nbsp;k</span><span style="color: #008000;"><br></span><span style="color: #000000;">cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">f[i][j]</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">endl;<br>}</span><span style="color: #008000;">//</span><span style="color: #008000;">end&nbsp;for&nbsp;i</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>}</span><span style="color: #008000;">//</span><span style="color: #008000;">end&nbsp;for&nbsp;j</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;tmp</span><span style="color: #000000;">=</span><span style="color: #000000;">f[</span><span style="color: #000000;">1</span><span style="color: #000000;">][n];<br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">(j</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">;j</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">n;</span><span style="color: #000000;">++</span><span style="color: #000000;">j)<br>{<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(f[j][n]</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">tmp)<br>tmp</span><span style="color: #000000;">=</span><span style="color: #000000;">f[j][n];<br>}</span><span style="color: #008000;">//</span><span style="color: #008000;">end&nbsp;for</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>cout&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">tmp</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">endl;<br><br>system(</span><span style="color: #000000;">"</span><span style="color: #000000;">pause</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}</span><span style="color: #008000;">//</span><span style="color: #008000;">end&nbsp;main<br></span></div>
<br> <img src ="http://www.cppblog.com/billhsu/aggbug/57083.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2008-07-24 21:37 <a href="http://www.cppblog.com/billhsu/archive/2008/07/24/57083.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>能量项链</title><link>http://www.cppblog.com/billhsu/archive/2008/07/23/56947.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Wed, 23 Jul 2008 07:37:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2008/07/23/56947.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/56947.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2008/07/23/56947.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/56947.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/56947.html</trackback:ping><description><![CDATA[挺好玩的一道题。。。<br>
NOIP2006的第一题。<br>
在Mars星球上，每个Mars人都随身佩带着一串能量项链。在项链上有N颗能量珠。能量珠是一颗有头标记与尾标记的珠子，这些标记对应着某个正整数。并
且，对于相邻的两颗珠子，前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样，通过吸盘（吸盘是Mars人吸收能量的一种器官）的作用，这两颗
珠子才能聚合成一颗珠子，同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为m，尾标记为r，后一颗能量珠的头标记为r，尾标记为n，则聚合后
释放的能量为m*r*n（Mars单位），新产生的珠子的头标记为m，尾标记为n。<br>
需要时，Mars人就用吸盘夹住相邻的两颗珠子，通过聚合得到能量，直到项链上只剩下一颗珠子为止。显然，不同的聚合顺序得到的总能量是不同的，请你设计一个聚合顺序，使一串项链释放出的总能量最大。<br>
例如：设N=4，4颗珠子的头标记与尾标记依次为(2，3) (3，5) (5，10) (10，2)。我们用记号&#8853;表示两颗珠子的聚合操作，(j&#8853;k)表示第j，k两颗珠子聚合后所释放的能量。则第4、1两颗珠子聚合后释放的能量为：<br>
(4&#8853;1)=10*2*3=60。<br>
这一串项链可以得到最优值的一个聚合顺序所释放的总能量为<br>
((4&#8853;1)&#8853;2)&#8853;3）=10*2*3+10*3*5+10*5*10=710。<br>
【输入文件】<br>
输入文件energy.in的第一行是一个正整数N（4&#8804;N&#8804;100），表示项链上珠子的个数。第二行是N个用空格隔开的正整数，所有的数均不超过
1000。第i个数为第i颗珠子的头标记（1&#8804;i&#8804;N），当i&lt;N&lt;
span&gt;时，第i颗珠子的尾标记应该等于第i+1颗珠子的头标记。第N颗珠子的尾标记应该等于第1颗珠子的头标记。<br>
至于珠子的顺序，你可以这样确定：将项链放到桌面上，不要出现交叉，随意指定第一颗珠子，然后按顺时针方向确定其他珠子的顺序。<br>
【输出文件】<br>
输出文件energy.out只有一行，是一个正整数E（E&#8804;2.1*109），为一个最优聚合顺序所释放的总能量。<br>
【输入样例】<br>
4<br>
2 3 5 10<br>
【输出样例】<br>
710<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">iostream</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">using</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">namespace</span><span style="color: #000000;">&nbsp;std;<br></span><span style="color: #0000ff;">#define</span><span style="color: #000000;">&nbsp;MAX&nbsp;100</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;n;</span><span style="color: #008000;">//</span><span style="color: #008000;">数量</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;f[MAX][MAX];<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;a[MAX];</span><span style="color: #008000;">//</span><span style="color: #008000;">a[i]为第i个珠子的值</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;k,i,j,r,tmp;<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;max(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;x,</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;y)<br>{<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(x</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">y)&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;x;<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;y;<br>}<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;main()<br>{<br>cin&nbsp;</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">n;<br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">n;</span><span style="color: #000000;">++</span><span style="color: #000000;">i)<br>{<br>cin&nbsp;</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">a[i];<br>}<br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">(i</span><span style="color: #000000;">=</span><span style="color: #000000;">2</span><span style="color: #000000;">;i</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">n;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">(j</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;j</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">n;j</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br>{<br>k</span><span style="color: #000000;">=</span><span style="color: #000000;">(i</span><span style="color: #000000;">+</span><span style="color: #000000;">j)</span><span style="color: #000000;">%</span><span style="color: #000000;">n;<br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">(r</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">;r</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">i;r</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br>f[j][k]</span><span style="color: #000000;">=</span><span style="color: #000000;">max(f[j][(j</span><span style="color: #000000;">+</span><span style="color: #000000;">r)</span><span style="color: #000000;">%</span><span style="color: #000000;">n]</span><span style="color: #000000;">+</span><span style="color: #000000;">f[(j</span><span style="color: #000000;">+</span><span style="color: #000000;">r)</span><span style="color: #000000;">%</span><span style="color: #000000;">n][k]</span><span style="color: #000000;">+</span><span style="color: #000000;">a[j]</span><span style="color: #000000;">*</span><span style="color: #000000;">a[(j</span><span style="color: #000000;">+</span><span style="color: #000000;">r)</span><span style="color: #000000;">%</span><span style="color: #000000;">n]</span><span style="color: #000000;">*</span><span style="color: #000000;">a[k],f[j][k]);<br>}<br>tmp</span><span style="color: #000000;">=-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">(i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">n;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">(f[i][i]</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">tmp)tmp</span><span style="color: #000000;">=</span><span style="color: #000000;">f[i][i];<br>cout</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">tmp</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">endl;<br>system(</span><span style="color: #000000;">"</span><span style="color: #000000;">pause</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}</span></div>
<br> <img src ="http://www.cppblog.com/billhsu/aggbug/56947.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2008-07-23 15:37 <a href="http://www.cppblog.com/billhsu/archive/2008/07/23/56947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>很好的递推题：铺磁砖和走格子</title><link>http://www.cppblog.com/billhsu/archive/2008/07/23/56948.html</link><dc:creator>Bill Hsu</dc:creator><author>Bill Hsu</author><pubDate>Wed, 23 Jul 2008 07:37:00 GMT</pubDate><guid>http://www.cppblog.com/billhsu/archive/2008/07/23/56948.html</guid><wfw:comment>http://www.cppblog.com/billhsu/comments/56948.html</wfw:comment><comments>http://www.cppblog.com/billhsu/archive/2008/07/23/56948.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/billhsu/comments/commentRss/56948.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/billhsu/services/trackbacks/56948.html</trackback:ping><description><![CDATA[<font color="#ff6600"><font color="#000000">这是</font></font>Matrix67.com的递推专项训练的题目，感觉很好。<font color="#ff6600"><br>
<br>
*题一：用1 x 1和2 x 2的磁砖不重叠地铺满N x 3的地板，共有多少种方案？<br>
样例输入：2<br>
样例输出：3</font><br>
<br>
先设一个f[i]表示i*3的地板铺的方法,f[1]=1;f[2]=3;<br>
i*3的地板数是这样得到的：(i-1)*3的地板比i*3的地板少的地方全铺上1*1的瓷砖，这有一种铺法；<br>
或者在(i-2)*3的地板比i*3的地板少的地方铺上2*2的瓷砖和2个1*1的瓷砖，这有两种铺法；<br>
所以得到递推式：<strong>f[i]=f[i-1]+2*f[i-2];</strong><br>
<br>
<font color="#ff6600"> *题二：从原点出发，一步只能向右走、向上走或向左走。恰好走N步且不经过已走的点共有多少种走法？<br>
样例输入：2<br>
样例输出：7</font><br>
<br>
这个我没想出来，看题解才弄明白。。<br>
先设一个f[i]表示恰好走i步且不经过已走的点 共有的走法。<br>
如果向上走，不会出现经过已走的点；如果向左或右，上一步不能是向右或左。<br>
<br>
引用题解上的一句话：/*<br>
<font color="#999999"> 这一步的选择数= (3*上一步的所有选择中向上走的选择数) + (2*上一步的所有选择中向左、右走的选择数)。上一步的所有选择中向上走的选择数&#8221;实际上就是&#8220;上上步的所有选择数&#8221;即d[i-2]<br>
</font> */引用结束<br>
<br>
还有一点，就是&#8220;上一步的所有选择中向左、右走的选择数&#8221; 等于 &#8220;上步所有的选择数(即f[i-1])-上步向上的选择数&#8221;<br>
也就等于 &#8220;上步所有的选择数(即f[i-1])-上上步所有的选择数(即f[i-2])&#8221;<br>
所以得到递推式：<strong>f[i] = (3*f[i-2]) + 2*(f[i-1]-f[i-2]);</strong><br>
<br>
题解上共有五题，都很好，大家可以去这里看看：<br>
http://www.fengzee.com/blog/article.asp?id=60 <img src ="http://www.cppblog.com/billhsu/aggbug/56948.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/billhsu/" target="_blank">Bill Hsu</a> 2008-07-23 15:37 <a href="http://www.cppblog.com/billhsu/archive/2008/07/23/56948.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>