<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_C++ Minor</title><subtitle type="text">Specializing in c / c + +, agorithms, games and puzzles, graphics, real-time rendering, computational mechanics, arts and design, etc. </subtitle><id>http://feed.cnblogs.com/blog/u/62688/rss</id><updated>2012-05-13T12:58:57Z</updated><author><name>atyuwen</name><uri>http://www.cnblogs.com/atyuwen/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/atyuwen/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/62688/rss"/><entry><id>http://www.cnblogs.com/atyuwen/archive/2012/05/13/live_coding.html</id><title type="text">HLSL Live Coding</title><summary type="text">Shader live coding是个很好玩的东西，因为只要你足够的创造力，仅用一个pixel shader几乎可以实现任意复杂的效果。正如iq所说：给我两个三角形，我就能画出整个世界。网上能够找到许多glsl的live coding tool. 但却一直没有找到hlsl的。这段时间稍微不那么忙了，于是自己写了一个hlsl版的，有兴趣的可以下载下来玩一玩。源代码在这里。最后贴一个视频，因为使用的fraps未注册，所以只能录30秒。视频中的效果是一个Sierpinski四面体，完整的ps代码可以在源码的save目录里找到。PlayPauseStop</summary><published>2012-05-13T11:58:00Z</published><updated>2012-05-13T11:58:00Z</updated><author><name>atyuwen</name><uri>http://www.cnblogs.com/atyuwen/</uri></author><link rel="alternate" href="http://www.cnblogs.com/atyuwen/archive/2012/05/13/live_coding.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/atyuwen/archive/2012/05/13/live_coding.html"/><content type="html">&lt;p&gt;Shader live coding是个很好玩的东西，因为只要你足够的创造力，仅用一个pixel shader几乎可以实现任意复杂的效果。正如iq所说：给我两个三角形，我就能画出整个世界。&lt;/p&gt;&lt;p&gt;网上能够找到许多glsl的live coding tool. 但却一直没有找到hlsl的。这段时间稍微不那么忙了，于是自己写了一个hlsl版的，有兴趣的可以&lt;a href="http://files.cnblogs.com/atyuwen/livecoding_rel.7z"&gt;下载&lt;/a&gt;下来玩一玩。&lt;/p&gt;&lt;p&gt;源代码在&lt;a href="https://github.com/atyuwen/hlsl_live_coding"&gt;这里&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;最后贴一个视频，因为使用的fraps未注册，所以只能录30秒。视频中的效果是一个Sierpinski四面体，完整的ps代码可以在源码的save目录里找到。&lt;/p&gt;&lt;p&gt;&lt;button onclick="javacript:live_coding_movie.play()"&gt;Play&lt;/button&gt;&lt;button onclick="javacript:live_coding_movie.stop()"&gt;Pause&lt;/button&gt;&lt;button onclick="javacript:live_coding_movie.stop();live_coding_movie.rewind()"&gt;Stop&lt;/button&gt; &lt;/p&gt;&lt;p&gt;&lt;object id="live_coding_movie" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="1280" height="760"&gt;&lt;param name="movie" value="http://files.cnblogs.com/atyuwen/live_coding.swf" /&gt;&lt;param name="play" value="false" /&gt;&lt;param name="loop" value="false" /&gt;&lt;embed src="http://files.cnblogs.com/atyuwen/live_coding.swf" width="1280" height="760" play="false" loop="false" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="transparent"/&gt;    &lt;/object&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/atyuwen/aggbug/2498300.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/atyuwen/archive/2012/05/13/live_coding.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/atyuwen/archive/2012/03/17/tonemapping.html</id><title type="text">Friendly Filmic Tonemapping</title><summary type="text">Filmic Tonemapping固然是个好东西，然而Jim Hejl &amp; Burgess-Dawson的原始公式在不少显示器上都显得过于鲜艳了，另外还有不少人甚至认为完全没有任何Tonemapping的画面更对他们的口味。众口难调，我们能做的就是提供一个可配置的Tonemapping，让他们自己撸去吧。Uncharted2中的Tonemapping是可配置的，而且参数还异常丰富灵活，有A, 有B, 有C, 还有D, E, F….，具体的公式我也懒得说了，大家都知道的，不知道的自己去翻ppt。你说有这么多的参数的公式好调么？-- 我反正是搞不定了。我需要的是一个简单粗暴的公式，只能有</summary><published>2012-03-17T06:32:00Z</published><updated>2012-03-17T06:32:00Z</updated><author><name>atyuwen</name><uri>http://www.cnblogs.com/atyuwen/</uri></author><link rel="alternate" href="http://www.cnblogs.com/atyuwen/archive/2012/03/17/tonemapping.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/atyuwen/archive/2012/03/17/tonemapping.html"/><content type="html">&lt;p&gt;Filmic Tonemapping固然是个好东西，然而Jim Hejl &amp;amp; Burgess-Dawson的原始公式在不少显示器上都显得过于鲜艳了，另外还有不少人甚至认为完全没有任何Tonemapping的画面更对他们的口味。众口难调，我们能做的就是提供一个可配置的Tonemapping，让他们自己撸去吧。&lt;/p&gt;&lt;p&gt;Uncharted2中的Tonemapping是可配置的，而且参数还异常丰富灵活，有A, 有B, 有C, 还有D, E, F&amp;#8230;.，具体的公式我也懒得说了，大家都知道的，不知道的自己去翻ppt。你说有这么多的参数的公式好调么？-- 我反正是搞不定了。我需要的是一个简单粗暴的公式，只能有一个参数，而且还需要这个参数的值跟画面的鲜艳程度有一个近似线性的关系。&lt;/p&gt;&lt;p&gt;于是把Jim Hejl &amp;amp; Burgess-Dawson的原始公式撸了一下，得到下面这个函数：&lt;/p&gt;// C = 0.8, gamma correction only&lt;br/&gt;// C = 0.39, gamma correction with filmic tonemapping&lt;br/&gt;half3 x = ExposureAdjust(linear_color);&lt;br/&gt;half3 t1 = 6.2 * x * x;&lt;br/&gt;half3 t2 = C * x;&lt;br/&gt;half3 y = (t1 + t2) / (t1 + 4.1 * t2 + 0.05) + (0.634 * C - 0.247) * x;&lt;p&gt;其中 C 的取值可在[0.3, 0.9] 之间调整(你非要超过这个区间它也不介意)，C值越低，画面越艳丽. 当 C=0.39时，几乎就是原始的filmic tonemapping (包含gamma correction, 如图1, 图2.) 而当 C=0.8时，就变成一个纯的 gamma correction (如图3.)&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/atyuwen/201203/201203171424513681.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="c_0_39" border="0" alt="c_0_39" src="http://images.cnblogs.com/cnblogs_com/atyuwen/201203/20120317142456711.png" width="244" height="240" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://images.cnblogs.com/cnblogs_com/atyuwen/201203/201203171424576642.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="c_0_39_2" border="0" alt="c_0_39_2" src="http://images.cnblogs.com/cnblogs_com/atyuwen/201203/20120317142459414.png" width="244" height="241" /&gt;&lt;/a&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/atyuwen/201203/201203171425013214.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="c_0_8" border="0" alt="c_0_8" src="http://images.cnblogs.com/cnblogs_com/atyuwen/201203/201203171425042884.png" width="244" height="240" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 8pt"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 图1： C = 0.39, x 属于 [0, 1]&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;图2： C = 0.39, x属于[0, 10]&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 图3：C = 0.8, x属于[0, 1]&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/atyuwen/aggbug/2403187.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/atyuwen/archive/2012/03/17/tonemapping.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/atyuwen/archive/2012/02/19/impossible_codification.html</id><title type="text">Impossible Codification</title><summary type="text">在iq的blog上看到这样一段代码:int t[] = {0x4845A956, 0x586DEE32, 0x7E6B9933, 0x0D059D58, 0};int ch = t[0] + t[1] + t[2] + t[3];t[0]^=ch;t[1]^=ch;t[2]^=ch;t[3]^=ch;char *str = (char*)t;把str打印出来是这样的：Egad! It WORKS!!而如果将t的改为这样：int t[] = {0x151ba3a, 0x10abc1a, 0x118a113, 0x1e08bc0b, 0 };那么此时str为: Hi, how are you?.看</summary><published>2012-02-19T10:44:00Z</published><updated>2012-02-19T10:44:00Z</updated><author><name>atyuwen</name><uri>http://www.cnblogs.com/atyuwen/</uri></author><link rel="alternate" href="http://www.cnblogs.com/atyuwen/archive/2012/02/19/impossible_codification.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/atyuwen/archive/2012/02/19/impossible_codification.html"/><content type="html">&lt;p&gt;在iq的&lt;a href="http://www.iquilezles.org/blog/?p=1733"&gt;blog&lt;/a&gt;上看到这样一段代码:&lt;/p&gt;int t[] = {0x4845A956, 0x586DEE32, 0x7E6B9933, 0x0D059D58, 0};&lt;br/&gt;int ch = t[0] + t[1] + t[2] + t[3];&lt;br/&gt;t[0]^=ch;&lt;br/&gt;t[1]^=ch;&lt;br/&gt;t[2]^=ch;&lt;br/&gt;t[3]^=ch;&lt;br/&gt;char *str = (char*)t;&lt;p&gt;把str打印出来是这样的：Egad! It WORKS!!&lt;/p&gt;&lt;p&gt;而如果将t的改为这样：&lt;/p&gt;int t[] = {0x151ba3a, 0x10abc1a, 0x118a113, 0x1e08bc0b, 0 };&lt;p&gt;那么此时str为: Hi, how are you?.&lt;/p&gt;&lt;p&gt;看起来很神奇吧。下面就来的推导一下怎么设置t的值，以使得str为任意字符串.&lt;/p&gt;&lt;p&gt;令 x = t[0], y = t[1], z = t[2], w = t[3]&lt;/p&gt;&lt;p&gt;我们需要将x, y, z, w经过指定的变换之后得到指定的x&amp;#8217;, y&amp;#8217;, z&amp;#8217;, w&amp;#8217;. 变换的过程为:&lt;/p&gt;&lt;blockquote style="margin-right: 0px" dir="ltr"&gt;&lt;p&gt;s = x + y + z + w&lt;/p&gt;&lt;p&gt;x&amp;#8217; = x ^ s&lt;/p&gt;&lt;p&gt;y&amp;#8217; = y ^ s&lt;/p&gt;&lt;p&gt;z&amp;#8217; = z ^ s&lt;/p&gt;&lt;p&gt;w&amp;#8217; = w ^ s&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;现在是已知x&amp;#8217;, y&amp;#8217;, z&amp;#8217;, w&amp;#8217;, 要求x, y, z, w.&amp;nbsp; 这看起来有点麻烦，因为有4个未知数，但稍稍变换一下可以发现，实际上只需要求一个未知数 s 就够了. 将上面的后四式两边同时异或一个s, 得:&lt;/p&gt;&lt;p&gt;x = x&amp;#8217; ^ s;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; y = y&amp;#8217; ^ s;&amp;nbsp;&amp;nbsp;&amp;nbsp; z = z&amp;#8217; ^ s;&amp;nbsp;&amp;nbsp;&amp;nbsp; w = w&amp;#8217; ^ s.&lt;/p&gt;&lt;p&gt;于是有方程：&lt;/p&gt;&lt;p&gt;s = (x&amp;#8217;^ s) + (y&amp;#8217; ^s) + (z&amp;#8217; ^s) + (w&amp;#8217;^s)&lt;/p&gt;&lt;p&gt;选定任意一个初始值，进行不动点迭代即可解得 s.&lt;/p&gt;&lt;p&gt;这里有两个疑问，一是方程的解是否存在，二是上面的迭代是否一定会收敛。答案都是肯定的，也很好证明。对于存在性可以得到，若方程右边和式的项数是偶数(在上面是4项)，则一定有解。而至于收敛性，因为一旦s的低位确定了，在迭代就不会变化了，而每次迭代至少会确定一个新的位，所于至多32次迭代就会收敛到解。感兴趣的同学可以自己推一下。&lt;/p&gt;&lt;p&gt;好了，现在我们也可以构造出神秘的编码了，试试下面这个：&lt;/p&gt;int t[10] = {0x33106d0f, 0x3351230e, 0x66457026, 0x3f526130,0x7e1b4d67, 0x7a487767, 0x721c682b, 0x764a6d2b, 0x133c0469, 0x133c0447};&lt;br/&gt;int ch = 0;&lt;br/&gt;for (int i = 0; i != 10; ++i) ch += t[i];&lt;br/&gt;for (int i = 0; i != 10; ++i) t[i] ^= ch;&lt;br/&gt;char *str = (char*)t;&lt;br/&gt;printf(str);&lt;img src="http://www.cnblogs.com/atyuwen/aggbug/2358441.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/atyuwen/archive/2012/02/19/impossible_codification.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/atyuwen/archive/2011/08/21/min_dot_product.html</id><title type="text">Minimum dot product query</title><summary type="text">Minimum dot product query (最小点积查询) : 若有一个二维向量集合V, 其大小为m. 那么在集合V上的一次最小点积查询即是说任意输入一个向量x, 返回在V中与x的点积最小的元素以及相应的点积，即 min{dot(x, vi) | vi 属于 V}。 这个问题是在cstheory.stackexchange上面看到的。楼主提出的问题原本是n维的最小点积查询，然后顺便提了...</summary><published>2011-08-21T07:15:00Z</published><updated>2011-08-21T07:15:00Z</updated><author><name>atyuwen</name><uri>http://www.cnblogs.com/atyuwen/</uri></author><link rel="alternate" href="http://www.cnblogs.com/atyuwen/archive/2011/08/21/min_dot_product.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/atyuwen/archive/2011/08/21/min_dot_product.html"/><content type="html">&lt;p&gt;Minimum dot product query (最小点积查询) : 若有一个二维向量集合V, 其大小为m. 那么在集合V上的一次最小点积查询即是说任意输入一个向量x, 返回在V中与x的点积最小的元素以及相应的点积，即 min{dot(x, vi) | vi 属于 V}。&lt;/p&gt;  &lt;p&gt;这个问题是在&lt;a href="http://cstheory.stackexchange.com/questions/7719/a-data-structure-for-minimum-dot-product-queries"&gt;cstheory.stackexchange&lt;/a&gt;上面看到的。楼主提出的问题原本是n维的最小点积查询，然后顺便提了下如果n=2, 则“immediate”就能得到一个(logm)^2的算法。我想了半天不知道他这个(logm)^2的复杂度是怎么弄出来的，但是事际上若n=2, 其实马上可以得到一个logm的算法。&lt;/p&gt;  &lt;p&gt;首先一个观察是x的长度并不影响最后的结果（忽略那个||x||倍的缩放），所以可以假设x均为单位向量， 于是任意dot(vi, x)即是vi在x方向上的投影。这就给了我们一个启发：最小点积只能在V的凸包顶点处获得。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/atyuwen/201108/201108212103421263.jpg"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="0" border="0" alt="0" src="http://images.cnblogs.com/cnblogs_com/atyuwen/201108/201108212103449080.jpg" width="367" height="322" /&gt;&lt;/a&gt; 图1： V（黑色）与x(蓝色)&lt;/p&gt;  &lt;p&gt;于是可以先求得V的凸包， 然后就将问题转化到求一个凸包投影到某个方向上后的端点。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/atyuwen/201108/201108212103466406.jpg"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="1" border="0" alt="1" src="http://images.cnblogs.com/cnblogs_com/atyuwen/201108/201108212103485062.jpg" width="367" height="322" /&gt;&lt;/a&gt; 图2: V 的凸包, 以及投影到x方向的最小点&lt;/p&gt;  &lt;p&gt;如果凸包的边向量依次形成一个序列E，那么求凸包投影到x方向上的最小点即相当于将x旋转90度后(见图2中红色箭头)插入到E中的合适位置上。这可以通过二分法来得到，只是需要定义一个合适的序。这个序可以用叉乘来定义，但是为了避免形成一个环，即出现a &amp;lt; b &amp;lt; c &amp;lt; d &amp;lt; a的情况, 一个方法是将向上的向量与向下的向量分开，如下所示：&lt;/p&gt;  bool less(const double2 &amp;amp;lhs, const double2 &amp;amp;rhs)&lt;br/&gt;{&lt;br/&gt;if (lhs.y &amp;gt;= 0 &amp;amp;&amp;amp; rhs.y &amp;lt; 0) return true;&lt;br/&gt;if (lhs.y == 0 &amp;amp;&amp;amp; rhs.y == 0 &amp;amp;&amp;amp; lhs.x &amp;gt; 0 &amp;amp;&amp;amp; rhs.x &amp;lt; 0) return true;&lt;br/&gt;return cross(lhs, rhs) &amp;gt; 0;&lt;br/&gt;}&lt;p&gt;序定义好了之后，直接std::lower_bound一下即可。整个算法的预处理时间为O(mlogm), 查询为O(logm), 这里还需要提一下的是空间复杂度，因为我们只需要存一个凸包即可，而随机分布在一个圆盘上的m个点其凸包的期望边数为O(m^(1/3)). 因此期望的空间复杂度为O(m^(1/3)).&lt;/p&gt;&lt;img src="http://www.cnblogs.com/atyuwen/aggbug/2147850.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/atyuwen/archive/2011/08/21/min_dot_product.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/atyuwen/archive/2011/03/09/visibility_query.html</id><title type="text">1-Dimensional Heightfield Visibility Query</title><summary type="text">The scientist builds in order to study, the engineer studies in order to build. -- Fred Brooks最近在忙各种毕业事项之余，一直在努力搞 Real-time GI ，可惜时间总是显得如此的不够用，搞完了 RSM 却忘了做 SRM，哈哈。为了避免长时间不思考算法问题，导致智商下降，决定弄个小问题来做一下。这个问题也是在搞 GI 的时候想到的，该问题的二维版本跟 GI 也算是有那么一丁点关系，尽管从原则上来说只用一个高度场来表示场景的话显然丢失了太多信息。前面都是废话，现在正式开始，问题是这样的：1-Dime</summary><published>2011-03-09T13:47:00Z</published><updated>2011-03-09T13:47:00Z</updated><author><name>atyuwen</name><uri>http://www.cnblogs.com/atyuwen/</uri></author><link rel="alternate" href="http://www.cnblogs.com/atyuwen/archive/2011/03/09/visibility_query.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/atyuwen/archive/2011/03/09/visibility_query.html"/><content type="html">&lt;p align="right"&gt;&lt;em&gt;The scientist builds in order to study, &lt;br /&gt;the engineer studies in order to build. &lt;br /&gt;-- Fred Brooks&lt;/em&gt;&lt;/p&gt;&lt;p&gt;最近在忙各种毕业事项之余，一直在努力搞 Real-time GI ，可惜时间总是显得如此的不够用，搞完了 RSM 却忘了做 SRM，哈哈。为了避免长时间不思考算法问题，导致智商下降，决定弄个小问题来做一下。这个问题也是在搞 GI 的时候想到的，该问题的二维版本跟 GI 也算是有那么一丁点关系，尽管从原则上来说只用一个高度场来表示场景的话显然丢失了太多信息。&lt;/p&gt;&lt;p&gt;前面都是废话，现在正式开始，问题是这样的：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;&lt;strong&gt;1-Dimensional Heightfield Visibility Query Problem&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;给定一个一维的高度场，可用数组 H 来表示，其中第 i 个元素 H[i] 代表点 i 处的高度，判断其中任意两点是否相互可见？&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;比如，若 H = {1, 0, 2, 2, 1, 3, 1, 0}，根据 H 可以绘制出一个轮廓如图 1 所示：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/atyuwen/heightfield.JPG" border="0" /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 图1：1维高度场示意图&lt;/p&gt;&lt;p&gt;我们想查询任意两个点 i, j 是否相互可见（用 visible(i, j) 来表示，另外在后文中均假设 i &amp;lt;= j）。比如，在图1中有 visible(2, 5) = true（见图中绿色虚线），而 visible(3, 6) = false（见图中红色虚线）。&lt;/p&gt;&lt;p&gt;这个问题说简单也简单，因为若要查询 visible(i, j)，只需要顺序从 H[i] 扫描到 H[j] ，判断一下斜率即可。这样每次查询的时间复杂度为 O(n)。&lt;/p&gt;&lt;p&gt;但是我们希望能做得更好，最好是能设计一个 online algorithm，先对 H 进行一下预处理，然后将每次查询的时间降为 O(1)。这当然可以做到，因为很明显我们可以预先将所有的 visible(i, j) 计算好并存储起来，这样的话需要 O(n^2) 的预处理时间，O(1) 的查询时间，同时需要 O(n^2) 的存储空间，为方便我们采用这样一种方式 &amp;lt;O(n^2), O(1) | O(n^2)&amp;gt; 来表示其复杂度。然而，当 n 较大时，这里 O(n^2) 的空间需求是不太能够接受的，如果你有过设计 online algorithm 的经验，此时的第一个想法可能会是看看能不能将空间复杂度降为 O(nlogn)，同时仍然维持 O(1) 的查询时间。&lt;/p&gt;&lt;p&gt;幸运的是，这的确是可能的，采用常规的 sparse table 就可以做到。当然，这里对 sparse table 的处理与经典的 RMQ 问题稍有差别，因为这里需要建立两个 sparse table。其基本动机基于以下观察：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;&lt;strong&gt;定理1&lt;/strong&gt;：对于任意一个点对 (i, j)，以及任意的另外两个点 k1, k2 位于 i, j 之间，且满足 k1 &amp;gt;= k2 &amp;#8211; 1。若用 partial(i, k, j) 来表示点 i 在经过 i 到 k 之间的所有点后是否还能看到点 j（意思是不考虑 k+1 到 j 之间的点是否构成遮挡），于是有：&lt;/p&gt;&lt;p&gt;visible(i, j) 当且仅当 partial(i, k1, j) 且 partial(j, k2, i)。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;定理1的证明很简单，在这里略过。事实上只要你想到它，那么它几乎就是不证自明的。若设 slope(i, k) 为点 i 在经过 i 到 k 之间的所有点后的最小未被遮挡斜率，那么只要知道 slop(i, k) 就能在 O(1) 时间内计算出 partial(i, k, j)。这个事实再加上定理1就构成了使用 sparse table 的基础：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;&lt;strong&gt;1. sparse table 的预计算过程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;对于每个点 i, 计算并存储 slope(i, i + 1), slope(i, i + 2), slope(i, i + 4), slope(i, i + 8), &amp;#8230;. 以及 slope(i, i &amp;#8211; 1), slope(i, i &amp;#8211; 2), slope(i, i &amp;#8211; 4), slope(i, i &amp;#8211; 8)&amp;#8230;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 查询过程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;若要查询 visible(i, j), 先计算出 k = 2^( floor(log2( j - i) ), 即不大于 j &amp;#8211; i 的最大2幂。然后从 sparse table 中查得 slope(i, i + k), slop(j, j &amp;#8211; k)，计算出 partial(i, i + k, j) 和 partial(j, j &amp;#8211; k, i)，从而得到 visible(i, j)。整个查询过程的时间复杂度为 O(1).&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;很遗憾在这里对 sparse table 的构造并不能像 RMQ 那样做到 O(nlogn)，如果直接暴力搞的话需要 O(n^2) 的时间，使得整个 online algorithm 的复杂度为 &amp;lt;O(n^2), O(1) | O(nlogn)&amp;gt;。所幸，通过一些简单的优化，可以大幅度的提高建立 sparse table 的效率，经过我测试的数千组数据表明，优化后的算法的期望复杂度很有可能是 &amp;lt;O(nlognlogn, O(1) | O(nlogn)&amp;gt;，但我并没有进行详细的分析，因为对于这个问题很难去假定其输入应该满足什么样的分布条件。在我所使用测试的数据中，每个点的高度值都是互相独立的随机数，这在直观上其实并不符合现实。&lt;/p&gt;&lt;p&gt;优化的方法说起来很麻烦，懒得讲了，感兴趣的可以在直接看&lt;a href="http://files.cnblogs.com/atyuwen/visibility_query.rar"&gt;源代码&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;如果不是要求查询时间一定为O(1)，那么下面这个方法也可能行得通。先建立一个 cartesian tree, 然后通过 LCA 来搞，对于两个点 (i, j)，若 LCA(i, j) != i &amp;amp;&amp;amp; LAC(i, j) != j，那么直接就可以返回 visible(i, j) = false. 否则若某个点是另一个点的祖先，比如 j 是 i 的祖先，那么可以在树中从 i 遍历到 j 来进行判断。中间也可以根据凸性建立一些额外的连接来进行优化。这样预处理时间和空间都为 O(n) ，查询时间最坏也为 O(n)，但大多数情况下应该非常快，因为 cartesian tree 的期望高度是 O(logn) 的，何况还有一堆优化手段可以搞，比如可以利用凸性建立一些额外的连接等等。哈，以后有时间再来尝试一下。&lt;/p&gt;&lt;p&gt;如果有人想到更好的方法，欢迎讨论&amp;#8230;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/atyuwen/aggbug/1979157.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/atyuwen/archive/2011/03/09/visibility_query.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/atyuwen/archive/2011/03/01/MultiresGI.html</id><title type="text">Stencil-Based Multiresolution Splatting Indirect Illumination</title><summary type="text">Stencil-Based Multiresolution Splatting的详细流程，英文很水，看的朋友请开启自动纠错。哈哈，这种风格其实是在模仿我的偶像之一：Erik Demaine.PDF下载: http://files.cnblogs.com/atyuwen/notes.pdf</summary><published>2011-03-01T13:49:00Z</published><updated>2011-03-01T13:49:00Z</updated><author><name>atyuwen</name><uri>http://www.cnblogs.com/atyuwen/</uri></author><link rel="alternate" href="http://www.cnblogs.com/atyuwen/archive/2011/03/01/MultiresGI.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/atyuwen/archive/2011/03/01/MultiresGI.html"/><content type="html">&lt;p&gt;Stencil-Based Multiresolution Splatting的详细流程，英文很水，看的朋友请开启自动纠错。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/atyuwen/1_low.jpg" border="0" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt="" src="http://images.cnblogs.com/cnblogs_com/atyuwen/2_low.jpg" border="0" /&gt;&lt;/p&gt;&lt;p&gt;哈哈，这种风格其实是在模仿我的偶像之一：Erik Demaine.&lt;/p&gt;&lt;p&gt;PDF下载: &lt;a href="http://files.cnblogs.com/atyuwen/notes.pdf"&gt;http://files.cnblogs.com/atyuwen/notes.pdf&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/atyuwen/aggbug/1968387.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/atyuwen/archive/2011/03/01/MultiresGI.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/atyuwen/archive/2011/02/02/eabs_closed_form.html</id><title type="text">求两个随机变量的差的绝对值的期望</title><summary type="text">问题1：给定离散随机变量 x 均匀分布在区间 [a, b] 的整点上，y 均匀分布在区间 [c, d] 的整点上，求期望 E(|x-y|)。问题很简单，显然最直接的办法就是枚举 x 和 y 然后进行统计即可。如果再稍稍思考一下，那么可以发现其实只用枚举其中一个变量就行了，因为若固定 x = i，那么求 E(|i-y|) 只需要对i &lt;=y 和i &gt; y 两种情况分别进行讨论即可。上面两个方法的运行时间都是与区间的大小相关的，对于这样简单的一个问题，有理由相信一定有 O(1) 的方法存在，事实上也的确如此，推导如下。首先可以交换 x , y 的顺序以保证 a &lt;= c，那么 a, b, c, d</summary><published>2011-02-02T04:13:00Z</published><updated>2011-02-02T04:13:00Z</updated><author><name>atyuwen</name><uri>http://www.cnblogs.com/atyuwen/</uri></author><link rel="alternate" href="http://www.cnblogs.com/atyuwen/archive/2011/02/02/eabs_closed_form.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/atyuwen/archive/2011/02/02/eabs_closed_form.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;问题1：给定离散随机变量 x 均匀分布在区间 [a, b] 的整点上，y 均匀分布在区间 [c, d] 的整点上，求期望 E(|x-y|)。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;问题很简单，显然最直接的办法就是枚举 x 和 y 然后进行统计即可。如果再稍稍思考一下，那么可以发现其实只用枚举其中一个变量就行了，因为若固定 x = i，那么求 E(|i-y|) 只需要对&amp;nbsp;i &amp;lt;=y 和&amp;nbsp;i &amp;gt; y 两种情况分别进行讨论即可。上面两个方法的运行时间都是与区间的大小相关的，对于这样简单的一个问题，有理由相信一定有 O(1) 的方法存在，事实上也的确如此，推导如下。&lt;/p&gt;&lt;p&gt;首先可以交换 x , y 的顺序以保证 a &amp;lt;= c，那么 a, b, c, d 之间的顺序可以分成 3 种情况：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;a &amp;lt;= b &amp;lt;= c &amp;lt;= d&lt;/li&gt;&lt;li&gt;a &amp;lt;= c &amp;lt; b &amp;lt;= d&lt;/li&gt;&lt;li&gt;a &amp;lt;= c &amp;lt;= d &amp;lt; b &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;对于第 1 种情况，因为 y 始终大于等于 x，因此 E(|x-y|) = E(y) &amp;#8211; E(x);&lt;/p&gt;&lt;p&gt;对于第 2 种情况，除了 cb 段以外 y 始终大于 x, 因此 E(|x-y|) = E(y) &amp;#8211; E(x) + p_cb_cb * e_cb_cb，这里的p_cb_cb 表示 x 和 y 都分布在 cb 段的概率，e_cb_cb 表示当 x 和 y 都分布在 cb 段时，|x-y|的期望。&lt;/p&gt;&lt;p&gt;对于第 3 种情况，可以将第 ab 拆成 ad 和 d&amp;#8217;b 两段，这里 d&amp;#8217; = d + 1。于是 E(|x-y|) = p_ad_cd * e_ad_cd + p_d&amp;#8217;b_cd * e_d&amp;#8217;b_cd，而 e_ad_cd 可以按第 2 种情况来求， e_d&amp;#8217;b_cd 可以按第 1 种情况来求，问题解决。&lt;/p&gt;&lt;p&gt;现在唯一剩下的问题就是如果求 e_cb_cb，显然若 b &amp;#8211; c + 1 = n，那么 e_cb_cb = e_[1, n]_[1, n]. 于是问题可以转换为：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;问题2：给定离散随机变量 x 和 y 均匀分布在区间 [1, n] 的整点上，求期望 E(|x-y|)。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;问题 2 简单地做一个求和就可以得到一个 closed form：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://www.codecogs.com/eqnedit.php?latex=\begin{align*} E_{n} &amp;amp;= \frac{1}{n^2}\sum_{i=1}^{n}{\sum_{j=1}^{n}{|i-j|}} =\frac{2}{n^2}\sum_{i=1}^{n}{\sum_{j=1}^{i}{(i-j)}} =\frac{2}{n^2}\sum_{i=1}^{n}{\sum_{k=1}^{i-1}{k}} \\ &amp;amp;= \frac{1}{n^2}\sum_{i=1}^{n}{(i^2-i)} =\frac{n^2-1}{3n} \end{align*}" target="_blank"&gt;&lt;img title="\begin{align*} E_{n} &amp;amp;= \frac{1}{n^2}\sum_{i=1}^{n}{\sum_{j=1}^{n}{|i-j|}} =\frac{2}{n^2}\sum_{i=1}^{n}{\sum_{j=1}^{i}{(i-j)}} =\frac{2}{n^2}\sum_{i=1}^{n}{\sum_{k=1}^{i-1}{k}} \\ &amp;amp;= \frac{1}{n^2}\sum_{i=1}^{n}{(i^2-i)} =\frac{n^2-1}{3n} \end{align*}" alt="" src="http://latex.codecogs.com/gif.latex?\begin{align*} E_{n} &amp;amp;= \frac{1}{n^2}\sum_{i=1}^{n}{\sum_{j=1}^{n}{|i-j|}} =\frac{2}{n^2}\sum_{i=1}^{n}{\sum_{j=1}^{i}{(i-j)}} =\frac{2}{n^2}\sum_{i=1}^{n}{\sum_{k=1}^{i-1}{k}} \\ &amp;amp;= \frac{1}{n^2}\sum_{i=1}^{n}{(i^2-i)} =\frac{n^2-1}{3n} \end{align*}" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;利用上式可以得到解决问题 1 的代码如下：&lt;/p&gt;double eabs(int a, int b, int c, int d)&lt;br/&gt;{&lt;br/&gt;    if (a &amp;gt; c) {swap(a, c); swap(b, d);}&lt;br/&gt;    if (b &amp;gt; d)&lt;br/&gt;    {&lt;br/&gt;        double e_ad_cd = eabs(a, d, c, d);&lt;br/&gt;        double p_ad_cd = (double)(d - a + 1) / (b - a + 1);&lt;br/&gt;        double e_db_cd = (b - c + 1) / 2.0;&lt;br/&gt;        double p_db_cd = (double)(b - d) / (b - a + 1);&lt;br/&gt;        return e_ad_cd * p_ad_cd + e_db_cd * p_db_cd;&lt;br/&gt;    }&lt;br/&gt;    int n = max(b - c + 1, 1);&lt;br/&gt;    double e_ab_cd = (c + d - a - b) / 2.0;&lt;br/&gt;    double e_cb_cb = (n - 1.0 / n) / 3.0;&lt;br/&gt;    double p_cb_cb = (double)n / (b - a + 1) * (double)n / (d - c + 1);&lt;br/&gt;    return e_ab_cd + e_cb_cb * p_cb_cb;&lt;br/&gt;}&lt;hr /&gt;&lt;p&gt;再来看如果随机变量是连续分布的那情况又如何：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;问题3：给定连续随机变量 x 均匀分布在区间 [a, b) 上，y 均匀分布在区间 [c, d) 上，求期望 E(|x-y|)。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;问题 3 同样可以根据 a, b, c, d 的顺序分成 3 种情况进行讨论，而在情况 2 中仍然还要碰到求 e_cb_cb 的问题。若 n = b - c，对于连续随机变量显然有 e_cb_cb = n * e_[0,1)_[0,1)，于是问题就转化成了：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;问题4：给定连续随机变量 x 和 y 均匀分布在区间 [0, 1) 上，求期望 E(|x-y|)。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;对于问题 4，可以直接求一个积分(实际上如果画出函数图像的话就是两个三棱锥)，也可以直接求极限：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://www.codecogs.com/eqnedit.php?latex=E_{[0,1)}=\lim_{n\rightarrow \infty}{\frac{E_n}{n}}=\lim_{n\rightarrow \infty}{\frac{n^2-1}{3n^2}}=\frac{1}{3}" target="_blank"&gt;&lt;img title="E_{[0,1)}=\lim_{n\rightarrow \infty}{\frac{E_n}{n}}=\lim_{n\rightarrow \infty}{\frac{n^2-1}{3n^2}}=\frac{1}{3}" alt="" src="http://latex.codecogs.com/gif.latex?E_{[0,1)}=\lim_{n\rightarrow \infty}{\frac{E_n}{n}}=\lim_{n\rightarrow \infty}{\frac{n^2-1}{3n^2}}=\frac{1}{3}" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;由上式可以得到解决问题 3 的代码如下：&lt;/p&gt;double eabs(double a, double b, double c, double d)&lt;br/&gt;{&lt;br/&gt;    if (a &amp;gt; c) {swap(a, c); swap(b, d);}&lt;br/&gt;    if (b &amp;gt; d)&lt;br/&gt;    {&lt;br/&gt;        double e_ad_cd = eabs(a, d, c, d);&lt;br/&gt;        double p_ad_cd = (d - a) / (b - a);&lt;br/&gt;        double e_db_cd = (b - c) / 2.0;&lt;br/&gt;        double p_db_cd = (b - d) / (b - a);&lt;br/&gt;        return e_ad_cd * p_ad_cd + e_db_cd * p_db_cd;&lt;br/&gt;    }&lt;br/&gt;    double n = max(b - c, 0.0);&lt;br/&gt;    double e_ab_cd = (c + d - a - b) / 2.0;&lt;br/&gt;    double e_cb_cb = n / 3.0;&lt;br/&gt;    double p_cb_cb = n / (b - a) * n / (d - c);&lt;br/&gt;    return e_ab_cd + e_cb_cb * p_cb_cb;&lt;br/&gt;}&lt;p&gt;最后祝大家兔年快乐!&lt;/p&gt;&lt;img src="http://www.cnblogs.com/atyuwen/aggbug/1948835.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/atyuwen/archive/2011/02/02/eabs_closed_form.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/atyuwen/archive/2011/01/20/petr_problem.html</id><title type="text">解题的艺术</title><summary type="text">Simplicity is relative. To the great majority of mankind– mathematical ignoramuses – it is a simple fact, for instance, that 17 X 17= 289, and a complicated one that in a principal ideal ring a finite subset of a set E suffices to generate the ideal generated by E. For the reader and for others amon</summary><published>2011-01-20T11:18:00Z</published><updated>2011-01-20T11:18:00Z</updated><author><name>atyuwen</name><uri>http://www.cnblogs.com/atyuwen/</uri></author><link rel="alternate" href="http://www.cnblogs.com/atyuwen/archive/2011/01/20/petr_problem.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/atyuwen/archive/2011/01/20/petr_problem.html"/><content type="html">&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p align="right"&gt;&lt;em&gt;Simplicity is relative. &lt;/em&gt;&lt;/p&gt;&lt;p align="right"&gt;&lt;em&gt;To the great majority of mankind&amp;nbsp;&amp;#8211; mathematical ignoramuses &amp;#8211; it is a simple fact, &lt;/em&gt;&lt;/p&gt;&lt;p align="right"&gt;&lt;em&gt;for instance, that 17 X 17= 289, and a complicated one &lt;/em&gt;&lt;/p&gt;&lt;p align="right"&gt;&lt;em&gt;that in a principal ideal ring a finite subset of a set E suffices to generate the ideal generated by E. &lt;/em&gt;&lt;/p&gt;&lt;p align="right"&gt;&lt;em&gt;For the reader and for others among a select few, the reverse is the case.&lt;/em&gt;&lt;/p&gt;&lt;p align="right"&gt;&lt;em&gt;-- Carl E. Linderholm&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;标题党一回，这篇文章其实并没有对解题的方法论进行探讨，而只是简单的对&lt;a href="http://petr-mitrichev.blogspot.com/"&gt;&lt;font color="#669966"&gt;Petr&lt;/font&gt;&lt;/a&gt;最近一篇&lt;a href="http://petr-mitrichev.blogspot.com/2011/01/nice-problem-to-test-formal-reasoning.html"&gt;&lt;font color="#669966"&gt;解题报告&lt;/font&gt;&lt;/a&gt;进行了一下翻译和整理。我一向不喜欢干翻译这事，但这回要破个例，因为难得有机会能见识到世界顶尖解题高手和算法高手对于一个问题的详细处理过程。&lt;/p&gt;&lt;p&gt;问题是这样的：你首先站在数轴的原点上，然交替地向左和向右移动，即先向左移动一步，再向右移动一步，再向左移动一步&amp;#8230;。现在给定两个正整数集合 A 和 B ，限制你在每次向左移动时，移动的距离必须是 A 中的一个元素，而向右移动时，移动的距离必须是 B 中的一个元素。判断你是否能通过这种交替移动到达整数轴上的任意位置。比如当 A = {1}, B = {1} 时，你显然只能在 &amp;#8211;1 和 0 两个点徘徊，而当 A = {1, 2}, B = {1, 2}时，此时你却可以轻易的到达任意位置。why? 先思考思考，想明白了就代表你理解题意了。&lt;/p&gt;&lt;p&gt;输入规模限制：集合 A 与 B 的大小不超过 100,000 ，而每个集合元素不大于 1,000,000,000。&lt;/p&gt;&lt;p&gt;首先遇到这个题目的时候，你发现必须要交替移动这个限制很讨厌，影响了你的思路。因此，一个自然的想法就是把先它搞掉。怎么搞？可以把向左的一步与接下来向右的一步合并为一大步。这样就得到一个新的整数集合 C = {b &amp;#8211; a | a 属于 A, b 属于 B}, 这个集合包含了所有 B 集合元素与 A 集合元素的差。于是现在题目的限制就变成了，首先你可以移动任意多步，其中每一步所移动的距离为 C 中的任意一个元素（移动的方向由该元素的正负号决定），最后你还可以选择是否向左移动一步，移动的距离可以为 A 中的任意一个元素。&lt;/p&gt;&lt;p&gt;现在先不考虑最后是否向左移动这一步，来看看如果只在 C 中进行移动的话可以达到哪些地方。显然，一个点 p 可以到达当且仅当&amp;nbsp;p 可以表示成 k1c1 + k2c2 + k3c3 + &amp;#8230;&amp;nbsp; 的形式，其中 ci 属于 C，而 ki 是非负整数。到这里 ki 必须非负这一条件又似乎有点麻烦，暂时先不管它，考虑若放宽条件，当 ki 可以取任意正整数时，所有的 p 形成的集合 P = {k1c1 + k2c2 + k3c3&amp;#8230;.} 是什么样子？&lt;/p&gt;&lt;p&gt;答案很简单，即 P = { kg | k 属于整数集Z} 为所有 g 的倍数所组成的集合，其中 g 为 C 中所有元素的最大公约数。这一结论用数学归纳法很容易证明。倘若你还知道一点抽象代数，那么可以知道 P 实际上是整数环上的一个理想，由于整数环是主理想整环，因此 P 还是个主理想，于是可以由一个元素生成，而这个元素正是 g。（写到这里的时候，又翻了翻龚昇老师的线代五讲，袭老师于2011年1月10日在北京逝世，祝愿老师在天堂走好！）&lt;/p&gt;&lt;p&gt;上面得到的结果可能会让你有继续下去的信心，但是别忘了前面我们忽略了 ki 不可以为负的条件。考虑这样一个问题：对于 C 中的任意一个数 c，你是否可以移动&amp;nbsp;&amp;#8211;c ？如果答案是&amp;#8220;可以&amp;#8221;，那么 ki 不能为负这个限制就可以安全的去掉。若 C 中的所有元素都是同号的，那么显然对于任意一个 c 你都不可能移动 -c，但此时最初的问题也已经解决了，因为 C 中所有元素同号意味着你最初的若干步都只能往一个方向走，虽然你最后还有一次向左走的机会，但此时败局已定，因此直接返回一个 false 即可。如果 C 中有正有负，即对于任意 c, 存在一个符号以其相反的数 d，那么可以先移动 |c| 次d，再移动 |d|&amp;nbsp;&amp;#8211; 1 次 c，总的移动距离为 |c|d + (|d|&amp;nbsp;&amp;#8211; 1) c =&amp;nbsp;&amp;#8211;c。哈，问题解决，运气不错。&lt;/p&gt;&lt;p&gt;总结一下前面所得到的结论，如果 C 中所有元素都为非正或非负，则可以直接返回 false，否则可以先移动到 g 的任意倍数位置，之后还可以选择是否向左再移动一步。&lt;/p&gt;&lt;p&gt;现在来考虑最后的这一步。由于在前面的移动中已经可以到达 g 的任意倍数位置，于是在经过最后一次移动后你可以到达位置 x 当且仅当 x 可以表示成 kg&amp;nbsp;&amp;#8211; a 的形式，其中 a 是 A 中的某个元素。注意到 x 所组成的集合 X = {kg&amp;nbsp;&amp;#8211; a} 也可以写成 X = { x | x =&amp;nbsp;-a mod g }，因此现在只需要注意 A 中所有元素模 g 后所得到的集合。&lt;/p&gt;&lt;p&gt;由于 g = gcd(a1&amp;nbsp;&amp;#8211; b1, b2&amp;nbsp;&amp;#8211; b1, b3&amp;nbsp;&amp;#8211; b1, &amp;#8230;}, 因此 ai&amp;nbsp;&amp;#8211; b1 可以被 g 整除。于是 ai&amp;nbsp;&amp;#8211; b1 这些元素之间的差 ai&amp;nbsp;&amp;#8211; aj 也可以被 g 整除，这就告诉我们：A 中的所有元素模 g 是同余的。也就是说 X 即为 { x | x =&amp;nbsp;&amp;#8211;a1 mod g}.&lt;/p&gt;&lt;p&gt;到这里，所有你可能到达的位置都已经找出来了，即所有 g 的倍数（若你选择不移动最后这一步），以及所有模 g&amp;nbsp;后等于&amp;nbsp;(&amp;#8211; a1 mod g) 的数（如果你选择最后再向左移动一步）。这两类数若想组成整个整数集，只能是以下两种情况：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;g = 1&lt;/li&gt;&lt;li&gt;g = 2 且 (a1 mod g) = 1&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;这样我们就得到了解决整个问题的算法如下：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;判断在 C 中是否有一个正数&lt;/li&gt;&lt;li&gt;判断在 C 中是否有一个负数&lt;/li&gt;&lt;li&gt;若上两步得到的答案不全为 true，则直接返回 false&lt;/li&gt;&lt;li&gt;算出 C 中所有元素的最大公约数 g&lt;/li&gt;&lt;li&gt;算出 a1 模 g 的结果 r&lt;/li&gt;&lt;li&gt;若 g = 1 或者 g = 2 且 r = 1，返回 ture&lt;/li&gt;&lt;li&gt;否则返回 false&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;问题似乎已经解决了，但是别忘了 C 的大小可能是 10 的 10 次方数量级。在上面的算法中，第 1 步和第 2 步显然不需要完全求出 C 即能得到答案，问题的关键在于第 4 步，怎么算出 C 中所有元素的最大公约数 g? 对于任意给定的一个集合，显然要求出其所有元素的最大公约数必须是 O(n) 的，但 C 并不是&amp;#8220;任意给定&amp;#8221;的集合，它是由所有形如 bi&amp;nbsp;&amp;#8211; aj 的元素所组成的。因此我们可以期望利用这个特殊性来寻找一个更快速的方法。&lt;/p&gt;&lt;p&gt;注意到 bi&amp;nbsp;&amp;#8211; aj = (bi&amp;nbsp;&amp;#8211; b1)&amp;nbsp;+ (b1&amp;nbsp;&amp;#8211; a1)&amp;nbsp;+ (a1&amp;nbsp;&amp;#8211; aj)，构造一个集合 D，其元素为 b1&amp;nbsp;&amp;#8211; a1、 所有的 bi&amp;nbsp;&amp;#8211; b1、以及所有的 a1 - aj。若 D 中所有元素的最大公约数为 s，则显然 s 能被 g 整除，因为在前面我们已经知道 A 中所有元素模 g 同余，同理 B 中所有元素也模 g 同余，于是 g 整除 bi&amp;nbsp;&amp;#8211; b1、a1 - aj，从而整除 s。另外，由于 C 中的每个元素都等于 D 中的 3 个元素之和，因此也有 s 整除 g。于是 s = g，这样就把求 g 的问题转化成了求 s。s 当然很好求，因为 D 的大小不会超过 200,000。我们终于搞定。&lt;/p&gt;&lt;p&gt;回顾一下解题的思路，你会发现整个过程虽然有点长，但其实每一步走过来都很自然。尽管有两个地方可能会卡一下，一是对 ki 不能为负的处理，二是求 C 中所有元素的最大公约数，但是认真思考一下很容易就能跨过去。本文到此为止，希望你能有所收获。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/atyuwen/aggbug/1940468.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/atyuwen/archive/2011/01/20/petr_problem.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/atyuwen/archive/2010/12/15/graffiti.html</id><title type="text">立体涂鸦的草图渲染</title><summary type="text">立体涂鸦（3D Street Painting, 3D Chalk Art, 3D Graffiti...）是一种很有意思的东西。前些年在网上经常能看到国外玩家的作品，比如这里；最近也有些国内的作品出现，比如这里。这玩意的原理其实很简单，比如前几天就有牛人写了一篇教程。我以前也尝试弄过，不过我对3d max不是很熟，也没有数码相机，没有他搞得那么专业，就是先渲染一张图，然后用light的projector map打在一个平面上，看起来效果也还不错。当然，如果不借助于3d max这样的软件，自己写个程序直接渲染出立体涂鸦的草图也并不是件难事。比如有一个模型o，放在一张纸p上，摄像机的位置为c，那</summary><published>2010-12-15T02:57:00Z</published><updated>2010-12-15T02:57:00Z</updated><author><name>atyuwen</name><uri>http://www.cnblogs.com/atyuwen/</uri></author><link rel="alternate" href="http://www.cnblogs.com/atyuwen/archive/2010/12/15/graffiti.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/atyuwen/archive/2010/12/15/graffiti.html"/><content type="html">&lt;p&gt;立体涂鸦（3D Street Painting, 3D Chalk Art, 3D Graffiti...）是一种很有意思的东西。前些年在网上经常能看到国外玩家的作品，比如&lt;a href="http://design.yesky.com/show/297/2391297.shtml"&gt;这里&lt;/a&gt;；最近也有些国内的作品出现，比如&lt;a href="http://macx.cn/a/a.htm?B=90&amp;amp;ID=1684333&amp;amp;ac=pre&amp;amp;rd=508275"&gt;这里&lt;/a&gt;。这玩意的原理其实很简单，比如前几天就有牛人写了一篇&lt;a href="http://www.thecodeway.com/blog/?p=1289"&gt;教程&lt;/a&gt;。我以前也尝试弄过，不过我对3d max不是很熟，也没有数码相机，没有他搞得那么专业，就是先渲染一张图，然后用light的projector map打在一个平面上，看起来效果也还不错。&lt;/p&gt;&lt;p&gt;当然，如果不借助于3d max这样的软件，自己写个程序直接渲染出立体涂鸦的草图也并不是件难事。比如有一个模型o，放在一张纸p上，摄像机的位置为c，那么需要做的仅仅就是将模型o中的任意顶点v按照cv的方向投影到p上。也可以把摄像机看成是一个光源，那么这里需要得到的就是o投影到p上的阴影。为了做到这一点，大概可以有以下一些方法：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;光线跟踪。如果手头上有现成的光线跟踪程序，那么只需将摄像机的成像窗口设为p的区域即可。&lt;/li&gt;&lt;li&gt;纹理采样。首先按照正常的方式渲染出o和p到一个RT中，然后再进行一个后处理的pass，对上一步得到的RT进行采样（类似于Shadow Map)。当然，这里也会有under-sampling的问题，但是从摄像机视角来看，分辨率总是一致的，因此不会有太大的走样。&lt;/li&gt;&lt;li&gt;修改观察矩阵和投影矩阵，这个应该是最简单的了，怎么修改下面会具体讲（都可以利用api而不需要手动对矩阵进行修改）。 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;现在来详细说说第三种方法。在正常的渲染模式下，摄像机的方向v以及投影近平面n的关系如下图所示：&lt;/p&gt;&lt;p align="center"&gt;&lt;img height="230" alt="" src="http://images.cnblogs.com/cnblogs_com/atyuwen/articles/o1.jpg" width="350" border="0" /&gt;&lt;/p&gt;&lt;p&gt;在上图中，摄像机的方向v正对着物体o，投影近平面n与v相垂直，且v与n的交点刚好位于n的正中心。为了渲染出涂鸦的草图，我们需要做以下调整：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;将摄像机的方向v调整到与p所在的平面相垂直。这个很简单，一个LookAt或者SetDirection之类的函数就搞定。注意，若新的视线方向与y轴平行（即p位于xz平面），最好重新设置一下摄像机的up vector，否则可能会出错。&lt;/li&gt;&lt;li&gt;调整投影近平面，使得摄像机的观察范围正好将p包括进内。这个可以用glFrustum，setFrustumExtents之类的函数进行设置。 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;调整后的摄像机观察方向以及投影近平面如下图所示，此时v与n的甚至连交点都没有了。&lt;/p&gt;&lt;p align="center"&gt;&lt;img height="244" alt="" src="http://images.cnblogs.com/cnblogs_com/atyuwen/articles/o2.jpg" width="350" border="0" /&gt;&lt;/p&gt;&lt;p&gt;好了，现在再来渲染一下看看，虽然看上去可能会有点变形，但是换个角度观察（最好用相机，手机也成，实在不行就闭上一只眼睛），说不定就能发现惊喜，比如下图就是一个例子：（用手机对着显示器拍的，模型是ogre中自带的knot）&lt;/p&gt;&lt;p align="center"&gt;&lt;img height="259" alt="" src="http://images.cnblogs.com/cnblogs_com/atyuwen/articles/2d.jpg" width="461" border="0" /&gt;&lt;/p&gt;&lt;p&gt;最后再帖一个视频，也是ogre中自带的一个模型，效果不太好，将就一看吧：&lt;/p&gt;&lt;p dir="ltr" style="margin-right: 0px" align="center"&gt;&amp;nbsp;&lt;embed align="center" src="http://player.youku.com/player.php/sid/XMjI5MzQxODky/v.swf" width="480" height="400" type="application/x-shockwave-flash" quality="high" allowscriptaccess="sameDomain"&gt;&lt;/p&gt;&lt;/embed&gt; &lt;img src="http://www.cnblogs.com/atyuwen/aggbug/1906048.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/atyuwen/archive/2010/12/15/graffiti.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/atyuwen/archive/2010/10/17/mandelbrot.html</id><title type="text">Benoit Mandelbrot</title><summary type="text">今天看到BenoitMandelbrot（分形理论创始人）于本月14日逝世，享年85岁。回想在两年前的纪录片《寻找隐秘的维度》中，Mandelbrot 还显得那么的年轻，一点也不像一个已逾八旬的老人，如今却已与世长辞，永远地消逝在另一个维度里。我一直对分形比较关注，也渲染过一些2D/3D的分形，下面帖出一些相关的资源，有兴趣的可以看看，了解一下 Mandelbrot 那醉人心弦的分形世界。纪录片：...</summary><published>2010-10-17T12:40:00Z</published><updated>2010-10-17T12:40:00Z</updated><author><name>atyuwen</name><uri>http://www.cnblogs.com/atyuwen/</uri></author><link rel="alternate" href="http://www.cnblogs.com/atyuwen/archive/2010/10/17/mandelbrot.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/atyuwen/archive/2010/10/17/mandelbrot.html"/><content type="html">&lt;p&gt;今天看到Benoit&amp;nbsp;Mandelbrot（分形理论创始人）于本月14日逝世，享年85岁。回想在两年前的纪录片《&lt;a href="http://movie.douban.com/subject/3773188/"&gt;寻找隐秘的维度&lt;/a&gt;》中，Mandelbrot 还显得那么的年轻，一点也不像一个已逾八旬的老人，如今却已与世长辞，永远地消逝在另一个维度里。&lt;/p&gt;&lt;p&gt;我一直对分形比较关注，也渲染过一些2D/3D的分形，下面帖出一些相关的资源，有兴趣的可以看看，了解一下 Mandelbrot 那醉人心弦的分形世界。&lt;/p&gt;&lt;ol&gt;&lt;li&gt;纪录片：《&lt;a href="http://movie.douban.com/subject/3773188/"&gt;寻找隐秘的维度&lt;/a&gt;》&lt;/li&gt;&lt;li&gt;纪录片：《&lt;a href="http://movie.douban.com/subject/3194941/"&gt;维度：数学漫步&lt;/a&gt;》&lt;/li&gt;&lt;li&gt;一个国内的网站：&lt;a href="http://www.cgpad.com/"&gt;http://www.cgpad.com/&lt;/a&gt;（似乎上不去了？），站长自己写了一个分形艺术创作软件叫做&lt;a href="http://cgpad.com/software/show/43"&gt;FerryMan Fractal&lt;/a&gt;&amp;nbsp;&lt;/li&gt;&lt;li&gt;iq大神的个人主页：&lt;a href="http://www.iquilezles.org/www/"&gt;http://www.iquilezles.org/www/&lt;/a&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;分形论坛：&lt;a href="http://www.fractalforums.com/"&gt;http://www.fractalforums.com/&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;我自己的两个链结：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Pixel Shader 画Sierpinski三角形：&lt;a href="http://hi.baidu.com/atyuwen/blog/item/6bb6d3f3f38f54c30b46e062.html"&gt;http://hi.baidu.com/atyuwen/blog/item/6bb6d3f3f38f54c30b46e062.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Pixel Shader 画Julia集：&lt;a href="http://hi.baidu.com/atyuwen/blog/item/6a357677320abc13b051b9bd.html"&gt;http://hi.baidu.com/atyuwen/blog/item/6a357677320abc13b051b9bd.html&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;最近写的一个Demo，是Mandelbrot Set的一种三维扩展：Mandelbulb，使用Ray marching进行渲染，Shader是从iq大神的Shader Toy上的一段glsl移植而来，做了稍许改动。截图如下：&lt;/p&gt;&lt;p&gt;&lt;img height="273" alt="" src="http://images.cnblogs.com/cnblogs_com/atyuwen/mandelblub.JPG" width="328" border="0" /&gt;&lt;/p&gt;&lt;p&gt;Demo下载：&lt;a href="http://files.cnblogs.com/atyuwen/Mandelbulb.rar"&gt;http://files.cnblogs.com/atyuwen/Mandelbulb.rar&lt;/a&gt;（很耗资源，慎重运行，切莫全屏）&lt;/p&gt;&lt;p&gt;操作方法：W/A/S/D 控制角度，UP/DOWN 控制距离&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/atyuwen/aggbug/1853790.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/atyuwen/archive/2010/10/17/mandelbrot.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
