【Codewars】7×7 摩天大樓

v2-b02ba5440139b21ee6a2ceba5158c0ed_1200x500

介紹

連接:7×7 Skyscrapersjava

C#答案(緣由:懶,可是徹底能夠轉成C++):bajdcc/learnstlgit

題目(機翻):github

在7乘7格的網格中,你只想在每一個廣場上放置一個摩天大樓,只有一些線索:數組

  • 摩天大樓的高度在1到7之間
  • 一行或一列中的全部摩天大樓樓層數量各不相同
  • 你只知道從外面的一行或一列中看到的摩天大樓的數量
  • 高層摩天大樓阻擋了後面的下層摩天大樓,致使你看不到後面的大樓了

你能寫一個能解決這個難題的程序嗎?函數

舉個例子,6x6的:測試

v2-a45496bad9d0aadfb3e2361ac5b8ad49_hd

6x6 摩天大樓 例優化

(有人說看不懂規則3和4,我就以圖來講明一下)3d

我根據上圖製做了一個假城市(bajdcc/UnityTest),以下:code

v2-9a35e16413c8e62d9ec55abd6c0a5d3d_r虛擬城市blog

咱們看線索中的左側(3,4,4):

v2-489542dd990bc52f26c035d8b8b58398_r規則3和4的說明

要求

輸入:int[]

v2-587af0b069f7696a90049be18391f65c_hd

輸入的數組下標

輸出:int[][]

分析

花了兩天思考這個系列的問題,最終固然是寫出來了(光想沒用)。

這個題目感受跟數獨很像,我最早想的思路就是一步步推理,直到解決問題,然而,4x4大小的推理規則在6x6大小的問題中,可能須要補充一些東西或有些東西不實用了,這就麻煩了。

老實說,作數獨題的時候,我不怎麼用窮舉法,我是對當前局面進行推理,利用排除法一步步肯定答案,但用代碼實現推理就變得困難了,雖然這樣作是最優的(由於根據不作多餘計算)。
推理不能用,那就老老實實用窮舉法吧,雖然窮舉法有點low,但只要能過就行。

題目中透露了一些可供優化的信息:各行各列中數是惟一的。這就意味着複雜度從O(n^n)降低到O(n!)。這跟八皇后有點像,但又有所不一樣,所以我就用回溯法作。

進一步思考

肯定用回溯作,也感受能夠借鑑八皇后的思路,還不能立刻開工,有幾個問題:

  1. 全排列的生成,這個嘛拿以前的代碼粘貼下
  2. 回溯遍歷的順序,這個順序大有文章

先解決全排列問題:抄了下https://github.com/bajdcc/jProlog/blob/master/src/com/bajdcc/rt/gen/array/RtNorepArray.java#L43 哈哈。

回溯的順序應該是怎樣呢?本身試嘍。

先生成全排列,而後計算從左邊向右看到的樓層數(假設爲Sky函數,Sky:=int->int),將結果存到字典中。

會發現,當n=7時,sky(7)=1,可能性最低,都算出來後,排序。

sky(7)<sky(6)<sky(5)<sky(1)<sky(4)<sky(3)<sky(2)

展開順序的話,我確定先找n=7的狀況的,由於這時的不肯定性最低(解只有一個),至關於能夠肯定一個格子的值了。

目前的思路是:找到值=7的數,就直接敲定一排解(1~7);再找值=6的數,這時答案不惟一,回溯;繼續找……

這樣運行程序的話,確定是耗時很長的,緣由是什麼?

再想想

咱們優化程序的目標是回溯時盡能夠減小回溯次數,那就必須在決定一個展開順序:先展開不肯定性小的,再展開不肯定性較大的。

有一種狀況,能夠減小不肯定性:若是一排格子的兩側都有數字(都不是零),那其實能夠將它們放到一塊兒回溯。例: 5 | x x x x x x x | 2,這樣能夠極大下降可能性。事實證實這樣作有一點效果。

思路有了:

  1. 將規則排好序(數大,對位匹配優先),回溯規則
  2. 保存現場,查看是否衝突,一是當前的測試值是否與該行/列衝突,二是測試值是否知足各行/列數惟一的原則
  3. 若是失敗,回溯
  4. 若是成功,level+=1,再測試下一個規則
  5. 若是level==規則總數,意味着經過了全部規則,此時還不能肯定解是否正確
  6. 規則有覆蓋不到的行/列,此時要將值是零的格子進行填空
  7. 填空的辦法是用排除法,而後不斷遍歷填空,若是最後填空失敗,則解不正確,若是填空成功,則解正確

注意點:

  1. 座標系問題,方向問題
  2. 判斷條件是否完備
  3. 儘可能用數組作(用list<>居然比int[]快。。)
  4. 等等細節問題

代碼比較囉嗦,460行,不貼了(別人寫得都很短簡直了)。

https://zhuanlan.zhihu.com/p/30713476備份。

相關文章
相關標籤/搜索