<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feed.answeror.com/styles/temp01.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link href="http://feed.answeror.com" type="application/rss+xml" rel="self"></atom:link><fs:self_link href="http://feed.feedsky.com/Helanic" type="application/rss+xml"></fs:self_link><lastBuildDate>Mon, 25 Apr 2011 15:52:10 GMT</lastBuildDate><title>Helanic Abyss</title><description>I am the answer.</description><link>http://www.answeror.com</link><sy:updatePeriod>hourly</sy:updatePeriod><sy:updateFrequency>1</sy:updateFrequency><language>en</language><pubDate>Fri, 29 Apr 2011 05:08:03 GMT</pubDate><item><title>A Quiz of C++ const</title><link>http://item.feedsky.com/~feedsky/Helanic/~8055388/604098387/5737218/1/item.html</link><content:encoded>&lt;p&gt;在vs2010环境下, 如下程序会输出什么?&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;#include &amp;lt;string&amp;gt;
#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;class T&amp;gt;
struct print;

template&amp;lt;&amp;gt;
struct print&amp;lt;int&amp;gt; { static string name() { return &quot;int&quot;; } };

template&amp;lt;class T&amp;gt;
struct print&amp;lt;T&amp;amp;&amp;gt; { static string name() { return print&amp;lt;T&amp;gt;::name() + &quot; &amp;amp;&quot;; } };

template&amp;lt;class T&amp;gt;
struct print&amp;lt;const T&amp;gt; { static string name() { return &quot;const &quot; + print&amp;lt;T&amp;gt;::name(); } };

// just utility functions above

struct S { int i; };

template&amp;lt;class T&amp;gt;
void foo(T) { cout &amp;lt;&amp;lt; print&amp;lt;T&amp;gt;::name() &amp;lt;&amp;lt; endl; }

template&amp;lt;class T&amp;gt;
void bar(T&amp;amp;) { cout &amp;lt;&amp;lt; print&amp;lt;T&amp;gt;::name() &amp;lt;&amp;lt; endl; }

int main() {
    int i;
    const int ci = 0;
    const int *pci = &amp;amp;i;
    S s;
    const S *pcs = &amp;amp;s;

    foo(i);
    foo(ci);
    foo(*pci);
    foo(pcs-&amp;gt;i);

    bar(i);
    bar(ci);
    bar(*pci);
    bar(pcs-&amp;gt;i);

    {
        auto a1 = i;
        auto a2 = ci;
        auto a3 = *pci;
        auto a4 = pcs-&amp;gt;i;
        cout &amp;lt;&amp;lt; print&amp;lt;decltype(a1)&amp;gt;::name() &amp;lt;&amp;lt; endl;
        cout &amp;lt;&amp;lt; print&amp;lt;decltype(a2)&amp;gt;::name() &amp;lt;&amp;lt; endl;
        cout &amp;lt;&amp;lt; print&amp;lt;decltype(a3)&amp;gt;::name() &amp;lt;&amp;lt; endl;
        cout &amp;lt;&amp;lt; print&amp;lt;decltype(a4)&amp;gt;::name() &amp;lt;&amp;lt; endl;
    }

    {
        auto&amp;amp; a1 = i;
        auto&amp;amp; a2 = ci;
        auto&amp;amp; a3 = *pci;
        auto&amp;amp; a4 = pcs-&amp;gt;i;
        cout &amp;lt;&amp;lt; print&amp;lt;decltype(a1)&amp;gt;::name() &amp;lt;&amp;lt; endl;
        cout &amp;lt;&amp;lt; print&amp;lt;decltype(a2)&amp;gt;::name() &amp;lt;&amp;lt; endl;
        cout &amp;lt;&amp;lt; print&amp;lt;decltype(a3)&amp;gt;::name() &amp;lt;&amp;lt; endl;
        cout &amp;lt;&amp;lt; print&amp;lt;decltype(a4)&amp;gt;::name() &amp;lt;&amp;lt; endl;
    }

    cout &amp;lt;&amp;lt; print&amp;lt;decltype(i)&amp;gt;::name() &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; print&amp;lt;decltype(ci)&amp;gt;::name() &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; print&amp;lt;decltype(*pci)&amp;gt;::name() &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; print&amp;lt;decltype(pcs-&amp;gt;i)&amp;gt;::name() &amp;lt;&amp;lt; endl;

    cout &amp;lt;&amp;lt; print&amp;lt;decltype((i))&amp;gt;::name() &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; print&amp;lt;decltype((ci))&amp;gt;::name() &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; print&amp;lt;decltype((*pci))&amp;gt;::name() &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; print&amp;lt;decltype((pcs-&amp;gt;i))&amp;gt;::name() &amp;lt;&amp;lt; endl;

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在还敢说你精通C++吗?&lt;/p&gt;
&lt;p&gt;答案参见&lt;a href=&quot;http://cpp-next.com/archive/2011/04/appearing-and-disappearing-consts-in-c/&quot;&gt;此文&lt;/a&gt;, 以及我的&lt;a href=&quot;http://wiki.answeror.com/cpp-next.appearing-and-disappearing-consts-in-cpp.note.html&quot;&gt;笔记&lt;/a&gt;.&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/604098387/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098387/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.answeror.com/archives/30579/feed</wfw:commentRss><slash:comments>1</slash:comments><description>在vs2010环境下, 如下程序会输出什么? #include &amp;#60;string&amp;#62; #include &amp;#60;iostream&amp;#62; using namespace std; template&amp;#60;class T&amp;#62; struct print; template&amp;#60;&amp;#62; struct print&amp;#60;int&amp;#62; { static string name() { return &quot;int&quot;; } }; template&amp;#60;class T&amp;#62; struct print&amp;#60;T&amp;#38;&amp;#62; { static string name() { return print&amp;#60;T&amp;#62;::name() + &quot; &amp;#38;&quot;; } }; template&amp;#60;class T&amp;#62; struct print&amp;#60;const T&amp;#62; { static string name() { return &quot;const &quot; + [...]&lt;img src=&quot;http://www1.feedsky.com/t1/604098387/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098387/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>const</category><category>c++</category><category>language</category><pubDate>Mon, 25 Apr 2011 23:52:10 +0800</pubDate><author>Answeror</author><comments>http://www.answeror.com/archives/30579#comments</comments><guid isPermaLink="false">http://www.answeror.com/?p=30579</guid><dc:creator>Answeror</dc:creator><fs:srclink>http://www.answeror.com/archives/30579</fs:srclink><fs:srcfeed>http://www.answeror.com/feed</fs:srcfeed><fs:itemid>feedsky/Helanic/~8055388/604098387/5737218</fs:itemid></item><item><title>宁静之雨</title><link>http://item.feedsky.com/~feedsky/Helanic/~8055388/604098388/5737218/1/item.html</link><content:encoded>&lt;p&gt;曾经无数次, 我有戳破自己耳膜的冲动.&lt;/p&gt;
&lt;p&gt;可是终究因为懦弱和理智无法将之付诸实践, 于是只好借助于音乐, 耳塞, 耳罩, 或者鼓起勇气去与噪音源交涉.&lt;/p&gt;
&lt;p&gt;以前无论我用何种方法, 都不可能做到在嘈杂的火车上心无旁骛地看书. 音乐大多会使我分心, 耳塞会伴随耳鸣, 耳罩又几近于隔靴搔痒, 每一种尝试均告失败.&lt;/p&gt;
&lt;p&gt;而今天晚上我竟然在回杭州的火车上拿着kindle饶有兴致地看了一个多小时的scheme, 读书效率估计达到了在实验室时的70%.&lt;/p&gt;
&lt;p&gt;一周前了解到白噪音的降噪妙用, 并在{ &lt;a href=&quot;http://www.naturesoundsmp3.net/thunderstorm-cd/&quot;&gt;http://www.naturesoundsmp3.net/thunderstorm-cd/&lt;/a&gt; }找到了这一段噪音终结者. 整整一小时的磅礴大雨, 伴随着远方隆隆的雷鸣, 让我得以随时随地感受到那种持久的宁静. 我一直以来对雨天的那种莫名的好感可能也来源于此.&lt;/p&gt;
&lt;p&gt;万物的嘈杂都被这雨水冲刷干净, 那种无法言喻的快乐久久回荡在我心头.&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/604098388/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098388/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.answeror.com/archives/30574/feed</wfw:commentRss><slash:comments>1</slash:comments><description>曾经无数次, 我有戳破自己耳膜的冲动. 可是终究因为懦弱和理智无法将之付诸实践, 于是只好借助于音乐, 耳塞, 耳罩, 或者鼓起勇气去与噪音源交涉. 以前无论我用何种方法, 都不可能做到在嘈杂的火车上心无旁骛地看书. 音乐大多会使我分心, 耳塞会伴随耳鸣, 耳罩又几近于隔靴搔痒, 每一种尝试均告失败. 而今天晚上我竟然在回杭州的火车上拿着kindle饶有兴致地看了一个多小时的scheme, 读书效率估计达到了在实验室时的70%. 一周前了解到白噪音的降噪妙用, 并在{ http://www.naturesoundsmp3.net/thunderstorm-cd/ }找到了这一段噪音终结者. 整整一小时的磅礴大雨, 伴随着远方隆隆的雷鸣, 让我得以随时随地感受到那种持久的宁静. 我一直以来对雨天的那种莫名的好感可能也来源于此. 万物的嘈杂都被这雨水冲刷干净, 那种无法言喻的快乐久久回荡在我心头.&lt;img src=&quot;http://www1.feedsky.com/t1/604098388/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098388/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>rain</category><category>white noise</category><category>silence</category><category>life</category><pubDate>Wed, 20 Apr 2011 22:48:32 +0800</pubDate><author>Answeror</author><comments>http://www.answeror.com/archives/30574#comments</comments><guid isPermaLink="false">http://www.answeror.com/?p=30574</guid><dc:creator>Answeror</dc:creator><fs:srclink>http://www.answeror.com/archives/30574</fs:srclink><fs:srcfeed>http://www.answeror.com/feed</fs:srcfeed><fs:itemid>feedsky/Helanic/~8055388/604098388/5737218</fs:itemid></item><item><title>Shortcut for Google Bookmarks</title><link>http://item.feedsky.com/~feedsky/Helanic/~8055388/604098389/5737218/1/item.html</link><content:encoded>&lt;blockquote&gt;&lt;p&gt;Click to add bookmark, and double click to manage bookmark. Assign any keyboard shortcut as you wish.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;一年前写给自己用的插件. 功能极其简陋. 应Google的要求把名字从&amp;#8221;Pure Google Bookmark&amp;#8221;改成现在的样子.&lt;/p&gt;
&lt;p&gt;下载: { &lt;a href=&quot;http://goo.gl/gKjTh&quot;&gt;http://goo.gl/gKjTh&lt;/a&gt; }&lt;/p&gt;
&lt;p&gt;代码: { &lt;a href=&quot;http://goo.gl/HFKOb&quot;&gt;http://goo.gl/HFKOb&lt;/a&gt; }&lt;/p&gt;
&lt;p&gt;写这个有几点心得:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;chrome没有提供监听双击事件的api, 自己用js计时器实现.&lt;/li&gt;
&lt;li&gt;chrome没有给插件提供快捷键支持, 需要自己写js注入到前台页面中去, 我用的是{ &lt;a href=&quot;http://goo.gl/6xpf&quot;&gt;http://goo.gl/6xpf&lt;/a&gt; }.&lt;/li&gt;
&lt;li&gt;localStorage, 正如其名字所示, 是每个页面独有的, 所以background.html和被注入js的页面的localStorage是不能共享的.&lt;/li&gt;
&lt;li&gt;前台页面不能使用&lt;code&gt;chrome.extension.getBackgroundPage()&lt;/code&gt;, 只能通过消息传递获得options.html里的设置.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;什么时候Google Reader, Google Docs和Google Bookmarks的标签功能集成到一块就好了. 或者是不是可以写个插件做集成呢&amp;#8230;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/604098389/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098389/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.answeror.com/archives/30569/feed</wfw:commentRss><slash:comments>0</slash:comments><description>Click to add bookmark, and double click to manage bookmark. Assign any keyboard shortcut as you wish.&lt;img src=&quot;http://www1.feedsky.com/t1/604098389/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098389/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>works</category><category>extension</category><category>chrome</category><category>google</category><category>bookmark</category><pubDate>Thu, 24 Mar 2011 21:13:47 +0800</pubDate><author>Answeror</author><comments>http://www.answeror.com/archives/30569#comments</comments><guid isPermaLink="false">http://www.answeror.com/?p=30569</guid><dc:creator>Answeror</dc:creator><fs:srclink>http://www.answeror.com/archives/30569</fs:srclink><fs:srcfeed>http://www.answeror.com/feed</fs:srcfeed><fs:itemid>feedsky/Helanic/~8055388/604098389/5737218</fs:itemid></item><item><title>C++临时变量的生命周期</title><link>http://item.feedsky.com/~feedsky/Helanic/~8055388/604098390/5737218/1/item.html</link><content:encoded>&lt;p&gt;下面这段程序:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;template&amp;lt;class T&amp;gt;
struct bar {
    T t;
    bar(T t) : t(t) {} //#3
    template&amp;lt;class U&amp;gt;
    bar(bar&amp;lt;U&amp;gt; other) : t(other.t) {} //#4
};
void foo(bar&amp;lt;const double&amp;amp;&amp;gt; b) {
    printf(&quot;%lf\n&quot;, b.t);
}
int main() {
    int a = 42;
    foo(bar&amp;lt;const double&amp;amp;&amp;gt;(a));//#1
    foo(bar&amp;lt;int&amp;gt;(a));          //#2
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;#1和#2虽然都能通过编译, 但是其中有一句是错的. 当然, 很明显#2看上去比较奇怪, 错的八成就是它, 可是初看上去却说不出它为什么错了.&lt;/p&gt;
&lt;p&gt;我们来看一个简单一点的例子:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;void foo(const double &amp;amp;arg) {}
int main() {
    int a = 42;
    foo(a);
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;相信这样一段代码没人会说它错. a被隐式转换为一个临时的double, 然后arg引用这个临时的double, 直到foo返回, 临时double销毁了. 我们很自然的认为这个临时的double的生命会延续到foo调用结束, 事实的确如此, 下面是C++标准对于这个过程的描述:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;12.2.3 [...] Temporary objects are destroyed as the last step in evaluating the fullexpression (1.9) that (lexically) contains the point where they were created. [...]&lt;/p&gt;
&lt;p&gt;1.9.12 A fullexpression is an expression that is not a subexpression of another expression.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;这个&amp;#8221;fullexpression&amp;#8221;显然就是指&lt;code&gt;foo(a);&lt;/code&gt;了.&lt;/p&gt;
&lt;p&gt;现在再来看看开头的例子.&lt;/p&gt;
&lt;p&gt;#1中, 在进入&lt;code&gt;bar&amp;lt;const double&amp;amp;&amp;gt;&lt;/code&gt;的构造函数#3之前, int被转换成一个临时的double, 这个double作为参数进入#3, 构造出一个临时的bar, 然后这个bar通过bar的拷贝构造函数(注意这时调用的是默认拷贝构造函数, 而不是#4)把这个临时的double传递给foo的形参. 根据上述标准, 这个临时的double是#1的一部分, 所以其生命周期一直延续到#1结束.&lt;/p&gt;
&lt;p&gt;#2中, 我们构造了一个临时对象&lt;code&gt;bar&amp;lt;int&amp;gt;&lt;/code&gt;, 我们暂且称其为x, 然后在将其赋给foo的形参b时调用了#4, 此时x.t在构造给b.t的时候产生了一个临时的double, 我们称其为y, 然后b.t引用了y, 进入函数foo&amp;#8230;&lt;/p&gt;
&lt;p&gt;问题在于y属于#2吗? 如果你把&amp;#8221;fullexpression&amp;#8221;理解成从取a的地址到foo返回CPU所执行的指令序列, 那么显然y当然是这一序列的一部分. 然而事实并非如此, &amp;#8220;fullexpression&amp;#8221;仅仅指#2这一行C++代码, 一串符号. 而y属于另一串符号&lt;code&gt;t(other.t)&lt;/code&gt;, 因为y的是在那里创建的, 于是也应该在那里销毁.&lt;/p&gt;
&lt;p&gt;最上面的代码原型是我在使用boost::tuple时遇到的, 为了简化问题, 就写了bar代替boost::tuple. 所以并不是说输入参数都写成const引用就好, 当遇到隐式类型转换的时候就要特别小心. 比如把tuple的模板参数写成某个类型的引用作为形参就不是什么好主意. 其它的比如optional, 内部保存引用也有很大风险. 不过因为optional没有泛型的单参数非explicit构造函数, 所以用它作为形参表示可选参数的时候被误用的概率通常比较小.&lt;/p&gt;
&lt;p&gt;这个问题的讨论参见&lt;a href=&quot;http://stackoverflow.com/questions/4526961/lifetime-of-implicitly-casted-temporaries&quot;&gt;这里&lt;/a&gt;.&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/604098390/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098390/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.answeror.com/archives/30560/feed</wfw:commentRss><slash:comments>0</slash:comments><description>下面这段程序: template&amp;#60;class T&amp;#62; struct bar { T t; bar(T t) : t(t) {} //#3 template&amp;#60;class U&amp;#62; bar(bar&amp;#60;U&amp;#62; other) : t(other.t) {} //#4 }; void foo(bar&amp;#60;const double&amp;#38;&amp;#62; b) { printf(&quot;%lf\n&quot;, b.t); } int main() { int a = 42; foo(bar&amp;#60;const double&amp;#38;&amp;#62;(a));//#1 foo(bar&amp;#60;int&amp;#62;(a)); //#2 return 0; } #1和#2虽然都能通过编译, 但是其中有一句是错的. 当然, 很明显#2看上去比较奇怪, 错的八成就是它, 可是初看上去却说不出它为什么错了. 我们来看一个简单一点的例子: void foo(const double [...]&lt;img src=&quot;http://www1.feedsky.com/t1/604098390/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098390/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>temporary</category><category>cpp</category><category>type-cast</category><category>lifetime</category><category>language</category><pubDate>Sat, 22 Jan 2011 21:16:41 +0800</pubDate><author>Answeror</author><comments>http://www.answeror.com/archives/30560#comments</comments><guid isPermaLink="false">http://www.answeror.com/?p=30560</guid><dc:creator>Answeror</dc:creator><fs:srclink>http://www.answeror.com/archives/30560</fs:srclink><fs:srcfeed>http://www.answeror.com/feed</fs:srcfeed><fs:itemid>feedsky/Helanic/~8055388/604098390/5737218</fs:itemid></item><item><title>boost::implicit_cast</title><link>http://item.feedsky.com/~feedsky/Helanic/~8055388/604098391/5737218/1/item.html</link><content:encoded>&lt;p&gt;在stackoverflow上看到&lt;a href=&quot;http://stackoverflow.com/questions/868306/what-is-the-difference-between-static-cast-and-implicit-cast&quot;&gt;这个帖子&lt;/a&gt;, 于是发现了boost::implicit_cast这个小东西.&lt;/p&gt;
&lt;p&gt;先来看看这段代码:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;struct top {};
struct mid_a : top {};
struct mid_b : top {};
struct bottom : mid_a, mid_b {};

void foo(mid_a&amp;#038;) {}
void foo(mid_b&amp;#038;) {}
void bar(bottom &amp;#038;arg) {
    foo(arg); // 想要调用&quot;void foo(mid_a&amp;#038;)&quot;
}

int main() {
    bottom x;
    bar(x);
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是无法编译通过的, 因为foo的重载解析有歧义. 那么把bar里的代码改一改, 为了保持C++风格, 我们使用static_cast, 而不是C风格的转换:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;foo(static_cast&amp;lt;mid_a&amp;&amp;gt;(arg));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;程序编译通过了, 运行起来也没有问题, 然而&amp;#8230;&lt;/p&gt;
&lt;p&gt;一个月以后我把bar的参数类型修改了一下:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;struct top {};
struct mid_a : top {};
struct mid_b : top {};
struct bottom : mid_a, mid_b {};

void foo(mid_a&amp;#038;) {}
void foo(mid_b&amp;#038;) {}
void bar(top &amp;#038;arg) {
    // ... 过了一个月, 这里已经添加了很多代码.
    foo(static_cast&amp;lt;mid_a&amp;&amp;gt;(arg));
}

int main() {
    top x;
    bar(x);
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;代码依旧编译通过, 可是运行时程序挂掉了(假设这几个类里面有许多成员, 并且在foo里对其进行了访问).&lt;/p&gt;
&lt;p&gt;发现问题了吗? 原因就在于static_cast太强大了, 强大到可以进行&amp;#8221;down-cast&amp;#8221;. 于是编译器没有给你任何警告, 就把一个top类型的引用给强制转换成了min_a的引用.&lt;/p&gt;
&lt;p&gt;这个时候轮到boost::implicit_cast出场了. 把bar里面的那句foo调用改一改:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;foo(boost::implicit_cast&amp;lt;mid_a&amp;&amp;gt;(arg));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是一个月前的代码依旧可以通过编译, 而一个月后的代码中的错误被编译器揪出来了. 原因在于隐式类型转换不允许&amp;#8221;down-cast&amp;#8221;, 只能&amp;#8221;up-cast&amp;#8221;.&lt;/p&gt;
&lt;p&gt;这里简要说一下所谓显式和隐式类型转换的区别. 在C++世界的英文里, 我们说&amp;#8221;convert&amp;#8221;通常指&amp;#8221;implicit convert&amp;#8221;, 而&amp;#8221;cast&amp;#8221;指&amp;#8221;explicit cast&amp;#8221;. 隐式类型转换好理解, 就是你写了个a=b, 而ab不同类型, 编译又不报错, 就说明隐式类型转换发生了, 类似的情况还有在函数调用的参数传递时. 而显式类型转换特指C风格的强制转换((type)obj或者C++中等价的type(obj)), 以及C++风格的四个关键字(static_cast, const_cast, dynamic_cast, reinterpret_cast). 然而这个定义是相当模糊的, 比如一个int类型的x, bool(x)是显式的, 而!!x是隐式的, 其实效果上并没有区别, 只是字面上的不同罢了. (关于cast和convert的区别, 参见&lt;a href=&quot;http://stackoverflow.com/questions/1374325/is-there-any-difference-between-type-casting-type-conversion&quot;&gt;这里&lt;/a&gt;和&lt;a href=&quot;http://stackoverflow.com/questions/4344402/c-and-c-difference-between-casting-and-conversion&quot;&gt;这里&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;所以在bar里我们需要的仅仅是一个隐式类型转换, 然而直接把arg传递给foo的话会出现重载歧义, 于是我们需要告诉编译器到底要进行哪个隐式类型转换. 然而static_cast又太过强大, 它还能做隐式类型转换之外的事情(up-cast), 于是在日后代码演化的过程中留下了bug.&lt;/p&gt;
&lt;p&gt;于是boost::implicit_cast应运而生, 它比static_cast弱, 正如它的名字一样, 它只能用来告诉编译器执行什么隐式类型转换.&lt;/p&gt;
&lt;p&gt;而它的代码呢? 简单到令人发指:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;template &amp;lt;typename T&amp;gt;
inline T implicit_cast (typename mpl::identity&amp;lt;T&amp;gt;::type x) {
    return x;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而mpl::identity的定义也极其简单:&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt; struct identity { typedef T type; };&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有人要问这个identity干什么用的, 看起来很累赘. 如果没有这个identity, 像&amp;#8221;implicit_cast(obj)&amp;#8221;这样的代码也能通过编译, 然而它其实什么也没做, obj的类型仍然没变. identity的存在使得函数模板的参数类型推导失效, 因为要推导出T, 首先得知道identity&lt;T&gt;是什么, 而identity又是依赖于T的. 于是就形成了循环依赖, 参数类型推导就失效了. 于是编译器就要求你显式地指定T的类型.&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/604098391/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098391/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.answeror.com/archives/30555/feed</wfw:commentRss><slash:comments>1</slash:comments><description>在stackoverflow上看到这个帖子, 于是发现了boost::implicit_cast这个小东西. 先来看看这段代码: struct top {}; struct mid_a : top {}; struct mid_b : top {}; struct bottom : mid_a, mid_b {}; void foo(mid_a&amp;#038;) {} void foo(mid_b&amp;#038;) {} void bar(bottom &amp;#038;arg) { foo(arg); // 想要调用&quot;void foo(mid_a&amp;#038;)&quot; } int main() { bottom x; bar(x); return 0; } 是无法编译通过的, 因为foo的重载解析有歧义. 那么把bar里的代码改一改, 为了保持C++风格, 我们使用static_cast, 而不是C风格的转换: foo(static_cast&amp;#60;mid_a&amp;#038;&amp;#62;(arg)); 程序编译通过了, 运行起来也没有问题, [...]&lt;img src=&quot;http://www1.feedsky.com/t1/604098391/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098391/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>cpp</category><category>type-cast</category><category>language</category><category>boost</category><pubDate>Wed, 29 Dec 2010 18:08:04 +0800</pubDate><author>Answeror</author><comments>http://www.answeror.com/archives/30555#comments</comments><guid isPermaLink="false">http://www.answeror.com/?p=30555</guid><dc:creator>Answeror</dc:creator><fs:srclink>http://www.answeror.com/archives/30555</fs:srclink><fs:srcfeed>http://www.answeror.com/feed</fs:srcfeed><fs:itemid>feedsky/Helanic/~8055388/604098391/5737218</fs:itemid></item><item><title>Koenig Lookup</title><link>http://item.feedsky.com/~feedsky/Helanic/~8055388/604098392/5737218/1/item.html</link><content:encoded>&lt;p&gt;Koenig Lookup, 别名ADL, 今天看&lt;a href=&quot;http://book.douban.com/subject/1463103/&quot;&gt;[The Boost Graph Library]&lt;/a&gt;的时候才想起来C++里还有这么一个东西.&lt;/p&gt;
&lt;p&gt;下面这段代码解释一切:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;namespace ns {
    struct type {};
    void foo(type) {}
    void foo(int) {}
    template&amp;lt;class T&amp;#038;gt
    void bar(T) {}
}
int main() {
    // Koenig Lookup
    foo(ns::type());
    //foo(1); // compile error
    bar(ns::type());
    //bar(1); // compile error
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用来做什么呢? wiki上有句话说得很好:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Within C++, functions found by ADL are considered part of a class&amp;#8217;s interface.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;BGL里对图结构的操作几乎都是通过非成员函数进行的, 非成员函数就是其接口的一部分, 于是ADL也就成了不可或缺的东西.&lt;/p&gt;
&lt;p&gt;以前从来没有对于大量非成员接口的需求, 所以也从没考虑过语言为什么会设计成这个样子, 这个语法为什么会存在, 所以即使看过, 并且经常用到(比如自定义swap), 到了该用的地方还是会傻乎乎的在函数前面加上个名字空间前缀. 类似的基础问题还有前几天写元函数平展tuple的时候(就是把嵌套的tuple平展开, 貌似很容易, 想想tuple里有引用类型和const限定符的话就没那么简单了)刚刚搞明白的关于const对于成员引用的作用, 具体说来就是下面的代码能够通过编译:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;struct foo {
    int &amp;#038;a;
    foo(int &amp;#038;a) : a(a) {}
};
int main() {
    int a;
    const foo f(a);
    f.a = 1;
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;#8220;勿在浮沙筑高台&amp;#8221;, 说起来容易做起来难, 恐怕有时候只有自己去搭一搭高台才能自知是浮沙.&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/604098392/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098392/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.answeror.com/archives/30552/feed</wfw:commentRss><slash:comments>5</slash:comments><description>Koenig Lookup, 别名ADL, 今天看[The Boost Graph Library]的时候才想起来C++里还有这么一个东西. 下面这段代码解释一切: namespace ns { struct type {}; void foo(type) {} void foo(int) {} template&amp;#60;class T&amp;#038;gt void bar(T) {} } int main() { // Koenig Lookup foo(ns::type()); //foo(1); // compile error bar(ns::type()); //bar(1); // compile error return 0; } 用来做什么呢? wiki上有句话说得很好: Within C++, functions found by ADL are considered [...]&lt;img src=&quot;http://www1.feedsky.com/t1/604098392/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098392/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>cpp</category><category>reference</category><category>koenig-lookup</category><category>const</category><category>language</category><pubDate>Wed, 22 Dec 2010 23:13:16 +0800</pubDate><author>Answeror</author><comments>http://www.answeror.com/archives/30552#comments</comments><guid isPermaLink="false">http://www.answeror.com/?p=30552</guid><dc:creator>Answeror</dc:creator><fs:srclink>http://www.answeror.com/archives/30552</fs:srclink><fs:srcfeed>http://www.answeror.com/feed</fs:srcfeed><fs:itemid>feedsky/Helanic/~8055388/604098392/5737218</fs:itemid></item><item><title>退役感言</title><link>http://item.feedsky.com/~feedsky/Helanic/~8055388/604098393/5737218/1/item.html</link><content:encoded>&lt;p&gt;ACM-ICPC不应该成为大学生活的全部, 但是我却时常后悔没有把我的全部投入进去.&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/604098393/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098393/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.answeror.com/archives/30546/feed</wfw:commentRss><slash:comments>1</slash:comments><description>ACM-ICPC不应该成为大学生活的全部, 但是我却时常后悔没有把我的全部投入进去.&lt;img src=&quot;http://www1.feedsky.com/t1/604098393/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098393/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>sense</category><category>acm-icpc</category><pubDate>Tue, 19 Oct 2010 19:51:52 +0800</pubDate><author>Answeror</author><comments>http://www.answeror.com/archives/30546#comments</comments><guid isPermaLink="false">http://www.answeror.com/?p=30546</guid><dc:creator>Answeror</dc:creator><fs:srclink>http://www.answeror.com/archives/30546</fs:srclink><fs:srcfeed>http://www.answeror.com/feed</fs:srcfeed><fs:itemid>feedsky/Helanic/~8055388/604098393/5737218</fs:itemid></item><item><title>{ZJU}{3408}{Gao}</title><link>http://item.feedsky.com/~feedsky/Helanic/~8055388/604098394/5737218/1/item.html</link><content:encoded>&lt;pre class=&quot;abstract&quot;&gt;-problem: 求10000个点50000条边的有向图上, 从0号点到所有点的所有最短路共经过i号点几次.
solution: dijkstra+拓扑排序/树形dp
--source: ZOJ Monthly, October 2010
----link: &lt;a href=&quot;http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3408&quot;&gt;http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3408&lt;/a&gt;
----code: &lt;a href=&quot;http://goo.gl/LmMT&quot;&gt;http://goo.gl/LmMT&lt;/a&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span id=&quot;more-30539&quot;&gt;&lt;/span&gt;&lt;br /&gt;
题目有点拗口, 简单说就是把0号点到所有点的所有最短路径列出来, 然后看看其中i出现了几次.&lt;/p&gt;
&lt;p&gt;设答案为ans[i], 则ans[i]=before[i]*after[i].&lt;br /&gt;
before[i]表示从0到i的最短路径数量, 这个可以在Dijsktra的过程中求出来.&lt;br /&gt;
after[i]表示以i为起点, 在0号点的到所有点的的最短路径图中有多少条路径.&lt;/p&gt;
&lt;p&gt;最短路径图是一个有向无环图, 可以用Dijkstra过程中记录的前驱来表示.&lt;br /&gt;
after的求法有两种: 树形DP或者拓扑排序, 本质是一样的.&lt;br /&gt;
用拓扑排序的话就是先将所有after置1, 然后对最短路径图做拓扑排序, 每次把当前点的after值累加到直连的点上.&lt;/p&gt;
&lt;p&gt;注意before和after的求解是分来的, 千万不要混在一起.&lt;/p&gt;
&lt;p&gt;题目的输出很阴险, 要求10位, 最后的乘法可能爆int64, 需要用到如下技巧:&lt;/p&gt;
&lt;pre class=&quot;isolate&quot;&gt;设 M=10^10, S=10^5,
则 a * b % M = (a / S * b % M * S + a % S * b) % M&lt;/pre&gt;
&lt;p&gt;另外注意区分&lt;em&gt;unidirectional&lt;/em&gt;和&lt;em&gt;undirected&lt;/em&gt;, 根本没有&lt;em&gt;undirectional&lt;/em&gt;这个词&amp;#8230;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/604098394/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098394/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.answeror.com/archives/30539/feed</wfw:commentRss><slash:comments>2</slash:comments><description>-problem: 求10000个点50000条边的有向图上, 从0号点到所有点的所有最短路共经过i号点几次. solution: dijkstra+拓扑排序/树形dp --source: ZOJ Monthly, October 2010 ----link: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3408 ----code: http://goo.gl/LmMT 题目有点拗口, 简单说就是把0号点到所有点的所有最短路径列出来, 然后看看其中i出现了几次. 设答案为ans[i], 则ans[i]=before[i]*after[i]. before[i]表示从0到i的最短路径数量, 这个可以在Dijsktra的过程中求出来. after[i]表示以i为起点, 在0号点的到所有点的的最短路径图中有多少条路径. 最短路径图是一个有向无环图, 可以用Dijkstra过程中记录的前驱来表示. after的求法有两种: 树形DP或者拓扑排序, 本质是一样的. 用拓扑排序的话就是先将所有after置1, 然后对最短路径图做拓扑排序, 每次把当前点的after值累加到直连的点上. 注意before和after的求解是分来的, 千万不要混在一起. 题目的输出很阴险, 要求10位, 最后的乘法可能爆int64, 需要用到如下技巧: 设 M=10^10, S=10^5, 则 a * b % M = (a / S * b % M * [...]&lt;img src=&quot;http://www1.feedsky.com/t1/604098394/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098394/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>shortest-path</category><category>dijkstra</category><category>tree-dp</category><category>high-precision</category><category>topsort</category><category>acm-icpc</category><pubDate>Thu, 07 Oct 2010 19:14:42 +0800</pubDate><author>Answeror</author><comments>http://www.answeror.com/archives/30539#comments</comments><guid isPermaLink="false">http://www.answeror.com/?p=30539</guid><dc:creator>Answeror</dc:creator><fs:srclink>http://www.answeror.com/archives/30539</fs:srclink><fs:srcfeed>http://www.answeror.com/feed</fs:srcfeed><fs:itemid>feedsky/Helanic/~8055388/604098394/5737218</fs:itemid></item><item><title>{HDU}{3613}{Best Reward}</title><link>http://item.feedsky.com/~feedsky/Helanic/~8055388/604098395/5737218/1/item.html</link><content:encoded>&lt;pre class=&quot;abstract&quot;&gt;-problem: 小写字母组成的长500000的串, 每种字母有一定的价值(可以为负), 要你一刀切成两个串, 总价值为两个串价值和, 若是回文, 则串的价值为每个字母价值和, 否则为0. 问最大价值多少.
solution: KMP求回文前缀
--source: 2010 ACM-ICPC Multi-University Training Contest（18）——Host by TJU
----link: &lt;a href=&quot;http://acm.hdu.edu.cn/showproblem.php?pid=3613&quot;&gt;http://acm.hdu.edu.cn/showproblem.php?pid=3613&lt;/a&gt;
----code: &lt;a href=&quot;http://goo.gl/BcQ6&quot;&gt;http://goo.gl/BcQ6&lt;/a&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span id=&quot;more-30537&quot;&gt;&lt;/span&gt;&lt;br /&gt;
一开始用后缀数组+RMQ. TLE, MLE什么的都出来了.&lt;/p&gt;
&lt;p&gt;想了一个晚上, 想到把反串接在原串后, 中间夹个$, 然后做KMP, 于是末尾的next域就指向了原串的最长回文前缀的末尾.&lt;br /&gt;
但是想到这里就想不下去了, Google一下&amp;#8221;回文前缀&amp;#8221;找到了Roba的一篇博文: &lt;a href=&quot;http://roba.rushcj.com/?p=439&quot;&gt;http://roba.rushcj.com/?p=439&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其实是KMP很简单的一个性质: &lt;strong&gt;对一个回文串s做一次KMP, 末尾的next域指向s的最长回文前缀的末尾.&lt;/strong&gt;&lt;br /&gt;
然后通过next, 从这个最长回文前缀继续往前跳, 就找到了下一个最长回文前缀&amp;#8230;&lt;/p&gt;
&lt;p&gt;于是这就是求一个串所有的回文前缀的方法了, 时空复杂度都是O(n).&lt;/p&gt;
&lt;p&gt;对于这题, 做完上述步骤之后把原串反过来, 重复上述步骤, 就找到了所有回文后缀, 于是只要线性扫一遍找最大值即可.&lt;/p&gt;
&lt;p&gt;为了保持&lt;strong&gt;[)区间&lt;/strong&gt;的一贯风格, 我把KMP也写成了next指向有效位下一位的形式.&lt;br /&gt;
这种好处只可意会不可言传, 一旦养成了这种前开后闭的思考习惯, 很多区间类问题就不容易写错了, 特别是字符串, 二分, DP等等.&lt;br /&gt;
真的很佩服STL的发明者.&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/604098395/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098395/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.answeror.com/archives/30537/feed</wfw:commentRss><slash:comments>0</slash:comments><description>-problem: 小写字母组成的长500000的串, 每种字母有一定的价值(可以为负), 要你一刀切成两个串, 总价值为两个串价值和, 若是回文, 则串的价值为每个字母价值和, 否则为0. 问最大价值多少. solution: KMP求回文前缀 --source: 2010 ACM-ICPC Multi-University Training Contest（18）——Host by TJU ----link: http://acm.hdu.edu.cn/showproblem.php?pid=3613 ----code: http://goo.gl/BcQ6 一开始用后缀数组+RMQ. TLE, MLE什么的都出来了. 想了一个晚上, 想到把反串接在原串后, 中间夹个$, 然后做KMP, 于是末尾的next域就指向了原串的最长回文前缀的末尾. 但是想到这里就想不下去了, Google一下&amp;#8221;回文前缀&amp;#8221;找到了Roba的一篇博文: http://roba.rushcj.com/?p=439 其实是KMP很简单的一个性质: 对一个回文串s做一次KMP, 末尾的next域指向s的最长回文前缀的末尾. 然后通过next, 从这个最长回文前缀继续往前跳, 就找到了下一个最长回文前缀&amp;#8230; 于是这就是求一个串所有的回文前缀的方法了, 时空复杂度都是O(n). 对于这题, 做完上述步骤之后把原串反过来, 重复上述步骤, 就找到了所有回文后缀, 于是只要线性扫一遍找最大值即可. 为了保持[)区间的一贯风格, 我把KMP也写成了next指向有效位下一位的形式. 这种好处只可意会不可言传, 一旦养成了这种前开后闭的思考习惯, 很多区间类问题就不容易写错了, 特别是字符串, 二分, DP等等. [...]&lt;img src=&quot;http://www1.feedsky.com/t1/604098395/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098395/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>palindrome</category><category>string</category><category>kmp</category><category>acm-icpc</category><pubDate>Mon, 04 Oct 2010 23:51:22 +0800</pubDate><author>Answeror</author><comments>http://www.answeror.com/archives/30537#comments</comments><guid isPermaLink="false">http://www.answeror.com/?p=30537</guid><dc:creator>Answeror</dc:creator><fs:srclink>http://www.answeror.com/archives/30537</fs:srclink><fs:srcfeed>http://www.answeror.com/feed</fs:srcfeed><fs:itemid>feedsky/Helanic/~8055388/604098395/5737218</fs:itemid></item><item><title>{HDU}{3225}{Flowers Placement}</title><link>http://item.feedsky.com/~feedsky/Helanic/~8055388/604098396/5737218/1/item.html</link><content:encoded>&lt;pre class=&quot;abstract&quot;&gt;-problem: 求n=200的二分图的完美匹配, 要求结果序列字典序第k小.
solution: dfs+继续增广路
--source: 2009 Asia Shanghai Regional Contest Host by DHU
----link: &lt;a href=&quot;http://acm.hdu.edu.cn/showproblem.php?pid=3225&quot;&gt;http://acm.hdu.edu.cn/showproblem.php?pid=3225&lt;/a&gt;
----code: &lt;a href=&quot;http://goo.gl/zkhk&quot;&gt;http://goo.gl/zkhk&lt;/a&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span id=&quot;more-30531&quot;&gt;&lt;/span&gt;&lt;br /&gt;
去年上海的Regional让我纠结了一整场的题目, 今天想起来把它过掉了.&lt;/p&gt;
&lt;p&gt;类似于一道网络流题目的连续增广路方法, 实现起来还是要想一会的.&lt;/p&gt;
&lt;p&gt;要求第k小的完美匹配, 很容易想到O(n^5)的dfs+hungary, 从编号最小的x点开始人为设定匹配的y点, 然后判断剩下的点是否能构成完美匹配.&lt;br /&gt;
这样当然要TLE的.&lt;/p&gt;
&lt;p&gt;我们在dfs之前先做一次hungary, 构造一个完美匹配.&lt;br /&gt;
然后回到之前的想法, 在dfs中枚举第x集第i个点的匹配点j的过程. 当j从j1变到j2时, 我们并不需要把之前构造好的lny(y集到x集的映射)全部清除. 我们只关心当i匹配j2的时候剩余点是否还能保持完美匹配, 换句话说就是撤销i到j1的匹配(lny[j1]=-1)之后是不是还能找到一条包含(i,j2)的增广路. 这不正是hungary算法的find过程干的事情吗? 如此一来只需要记录好上层dfs已经匹配好的点, 然后在枚举本层的匹配点时不断修改lny然后找增广路即可.&lt;/p&gt;
&lt;p&gt;复杂度O(n^3).&lt;/p&gt;
&lt;p&gt;需要注意的是每次找增广路之前都需要清空hungary算法的use(记录y集点是否被访问过)数组, 以及找增广路的时候不要破坏上层dfs已经建立好的匹配.&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/604098396/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098396/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://www.answeror.com/archives/30531/feed</wfw:commentRss><slash:comments>0</slash:comments><description>-problem: 求n=200的二分图的完美匹配, 要求结果序列字典序第k小. solution: dfs+继续增广路 --source: 2009 Asia Shanghai Regional Contest Host by DHU ----link: http://acm.hdu.edu.cn/showproblem.php?pid=3225 ----code: http://goo.gl/zkhk 去年上海的Regional让我纠结了一整场的题目, 今天想起来把它过掉了. 类似于一道网络流题目的连续增广路方法, 实现起来还是要想一会的. 要求第k小的完美匹配, 很容易想到O(n^5)的dfs+hungary, 从编号最小的x点开始人为设定匹配的y点, 然后判断剩下的点是否能构成完美匹配. 这样当然要TLE的. 我们在dfs之前先做一次hungary, 构造一个完美匹配. 然后回到之前的想法, 在dfs中枚举第x集第i个点的匹配点j的过程. 当j从j1变到j2时, 我们并不需要把之前构造好的lny(y集到x集的映射)全部清除. 我们只关心当i匹配j2的时候剩余点是否还能保持完美匹配, 换句话说就是撤销i到j1的匹配(lny[j1]=-1)之后是不是还能找到一条包含(i,j2)的增广路. 这不正是hungary算法的find过程干的事情吗? 如此一来只需要记录好上层dfs已经匹配好的点, 然后在枚举本层的匹配点时不断修改lny然后找增广路即可. 复杂度O(n^3). 需要注意的是每次找增广路之前都需要清空hungary算法的use(记录y集点是否被访问过)数组, 以及找增广路的时候不要破坏上层dfs已经建立好的匹配.&lt;img src=&quot;http://www1.feedsky.com/t1/604098396/Helanic/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/Helanic/~8055388/604098396/5737218/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>dfs.hungary</category><category>bipartite-graph.augmenting-path</category><category>acm-icpc</category><pubDate>Mon, 04 Oct 2010 16:24:00 +0800</pubDate><author>Answeror</author><comments>http://www.answeror.com/archives/30531#comments</comments><guid isPermaLink="false">http://www.answeror.com/?p=30531</guid><dc:creator>Answeror</dc:creator><fs:srclink>http://www.answeror.com/archives/30531</fs:srclink><fs:srcfeed>http://www.answeror.com/feed</fs:srcfeed><fs:itemid>feedsky/Helanic/~8055388/604098396/5737218</fs:itemid></item></channel></rss>
