日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

重构-打造爱因斯坦谜题最快算法

發(fā)布時間:2025/3/19 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 重构-打造爱因斯坦谜题最快算法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

  上一篇里,闡述了解這道題的思路,并在代碼上實現(xiàn)。不過代碼還有很多可改進之處。性能方面,雖然比窮舉法快得多,此外搜索算法還是比較盲目,效率應(yīng)該能更上一層樓。

  首先是在算法實現(xiàn)最后一步的搜索樹遞歸方法中,發(fā)現(xiàn)MatchResult枚舉并沒有實際用處

var result = conditions[node.Index].Match(guys, ref attempts);if (result == MatchResult.Fail){if (node.Action != null) node.Action.RollBack();node = node.Parent.Next();}else{node = node.Expand(attempts).Next();}

  我們只需要知道Condition匹配是否成功即可,如果想知道更詳細(xì)情況,可以結(jié)合參數(shù)中的attempts在執(zhí)行后的結(jié)果。這種無端增加復(fù)雜度的東西,當(dāng)然要砍掉。Condition抽象類定義變成:

abstract class Condition{……public abstract bool Match(IList guys, ref IList attempts);}

  現(xiàn)在去掉MatchResult枚舉,除了Condition類,還影響Guy類的VerfyProperty方法。

public MatchResult VerifyProperty(Property property, IList attempts);

  我把它改成了返回bool類型,總是覺得有點別扭。又是在上班路上,想到了,是因為它違反了Shy原則,出現(xiàn)在了不該出現(xiàn)的地方。Guy類不應(yīng)該直接與Attemp打交道。那VerfyProperty方法應(yīng)該出現(xiàn)在哪里,Condition類中?也是別扭,這樣要多傳一個Guy參數(shù),主要是它和Condition類中的Properties沒直接聯(lián)系。反復(fù)斟酌,想到了擴展方法。

static class PuzzleExtension{public static Boolean TryAdd(this IList attempts, Guy guy, Property property);public static Boolean TryAdd(this IList attempts, Guy guy, Property[] properties);public static Boolean TryAdd(this IList attempts, Guy guy1, Guy guy2, Property[] properties);}

  這樣就比較舒暢了,為貧血模型的進行充血,看來這才是擴展方法的陽關(guān)大道。

  對于Condition.Match方法在兩個子類實現(xiàn),尤其是AdjacentCondition,相當(dāng)?shù)姆爆?#xff0c;行數(shù)近百,一眼望去就感覺有許多重復(fù)代碼。嘗試各種優(yōu)化,費盡九牛之力,精簡了一些代碼,但還是很多。最后,使用Builder模式對Match方法進行拆分,變成這樣:

abstract class Condition{......public Boolean Match(IList guys, ref IList attempts){var availGuys = this.SearchGuy(guys);Guy guy1 = availGuys[0], guy2 = availGuys[1];if (attempts == null) attempts = new List();else attempts.Clear();if (guy1 == null && guy2 == null)return MatchBothNull(guys, attempts);else if (guy1 == guy2)return MatchEqual();else if (guy1 == null ^ guy2 == null)return MatchOneNull(guy1, guy2, attempts);elsereturn MatchNotEqual(guy1, guy2);}protected abstract Boolean MatchOneNull(Guy guy1, Guy guy2, IList attempts);protected abstract Boolean MatchBothNull(IList guys, IList attempts);protected abstract Boolean MatchEqual();protected abstract Boolean MatchNotEqual(Guy guy1, Guy guy2);public abstract Int32 CountPaths(IList guys);......}

  兩個子類分別要重寫四個方法,這樣每個方法里的代碼量就少了,可以控制在一頁以內(nèi)。不過AdjacentCondition的MatchOneNull方法還是超過了25行,里面就是兩種情況變換,邏輯上明顯重復(fù),但要強行合并的話,必然要引入新變量,結(jié)果得不償失,不知道大家有什么好辦法。

protected override Boolean MatchOneNull(Guy guy1, Guy guy2, IList attempts){ int posKnown, posLeft, posRight; // left/right means match guy1 is on the left/right of guy2Property propToFind; //The property match no guyif (guy1 == null) //1 for null, 2 for not null{posKnown = guy2[PN.Postion];posLeft = posKnown - 1; posRight = posKnown + 1;propToFind = Properties[0];}else{posKnown = guy1[PN.Nation];posLeft = posKnown + 1;posRight = posKnown - 1;propToFind = Properties[1];}if (posLeft > 0 && posLeft < 6){var leftGuy = GuyRuler.Single(posLeft);attempts.TryAdd(leftGuy, propToFind);}if (posRight > 0 && posRight < 6 && Relation == RelativePosition.Both){var rightGuy = GuyRuler.Single(posRight);attempts.TryAdd(rightGuy, propToFind);}return attempts.Count > 0;}

  強龍難壓地頭蛇,只能暫時睜一只眼閉一只眼了。畢竟還有更重要的事情,優(yōu)化算法。

  再分析一下條件,或者干脆我們自己手工把這道題解一遍,就會發(fā)現(xiàn),前面真的走了很多彎路。比如我們已經(jīng)知道“挪威人住在第一個房子裏(最左邊)“,下面又有個條件"挪威人和住藍(lán)房子的人相鄰”,便能確定第二個人住藍(lán)房子,篩選范圍就縮小許多。我們也可以將各個AddCondition語句順序換一下,可以看到遞歸查找的次數(shù)差別很懸殊。所以,我們不要運氣決定性能,自己的命運自己作主,主動去找最容易打開突破口的機會。

  首先,我們讓Condtion實例具備新的能力 — 即探路能力。

abstract class Condition{......public abstract Int32 CountPaths(IList guys);......}

  從而可以計算下一步的選擇有多少,我們可以比較每個條件,找出分支最少的選擇,再進行嘗試。

Condition searchCondition(){int minBranchCount = int.MaxValue ;Condition condition = null ;foreach (var item in conditions){var count = item.CountPaths(guys);if (count <= 1) return item;if (count < minBranchCount){minBranchCount = count;condition = item;}}return condition;}

  讓我們在茫茫黑夜中,找到了指路的明燈,趕緊來試一下吧。

輪數(shù)(1000次/輪)

1

2

3

4

時間(ms)

80

66

66

66

  平均每次解題不到0.0001秒!過程中只遞歸了13次。切記是在Release模式下運行,Debug模式慢太多。據(jù)我所知,這是目前最快的算法,這就是面向?qū)ο笏惴ǖ臐摿?#xff01;

  下一步,還要繼續(xù)深入研究這部內(nèi)容,不知道這種思想能否用在其他智力運算題,如背包問題,二十四點上面。研究人工智能,還真挺有趣。

轉(zhuǎn)載于:https://www.cnblogs.com/XmNotes/archive/2010/10/26/1861793.html

總結(jié)

以上是生活随笔為你收集整理的重构-打造爱因斯坦谜题最快算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。