1. 程式人生 > 其它 >IDA*、操作打表、並行處理-The Rotation Game HDU - 1667

IDA*、操作打表、並行處理-The Rotation Game HDU - 1667

萬惡之源

優秀題解

用文字終究難以窮盡程式碼的思想

思路

每次操作都有八種選擇,相當於一棵每次延申八個子節點的搜尋樹,故搜尋應該是一種方法。而這題要求求最少步數,我們就可以想到可以試試迭代加深搜尋(但其實我做它因為它是書本的習題)。再搭配一個估值函式來剪枝就很香啦。

輪換方塊(操作打表)

我的原始思路十分粗暴,就是用一個二維陣列來儲存這個“#”圖形,但是這會十分浪費空間,在寫輪換操作時的程式碼時也很繁冗。
我學到的呢,是用一維陣列來儲存這個圖形,也就是直接用題目的輸入生成一個數組。這樣進行輪換操作可能不如二維的直觀,但熟悉熟悉就好吧。所以應該如何輪換呢?這其實相當於一個對映,由於每個元素在原來的圖形的位置是獨特的,那將原圖形一維化之後,這個元素的位置也仍然是獨特的。因此,我們只需要找出,原來“#”圖形的某一列/行在一維陣列的對應座標就好。
但是由於資料規模不大,我們可以打表來實現,也就是事先找出某個操作需要使用的座標。

const int index[8][7] = {  //從A-H操作變動的下標
    { 0,2,6,11,15,20,22 },    //A
    { 1,3,8,12,17,21,23 },    //B
    { 10,9,8,7,6,5,4 },       //C
    { 19,18,17,16,15,14,13 }, //D
    { 23,21,17,12,8,3,1 },    //E
    { 22,20,15,11,6,2,0 },    //F 
    { 13,14,15,16,17,18,19 }, //G
    { 4,5,6,7,8,9,10 },       //H
};

可行性剪枝(估值函式)

再做這題之前我做了另外一題,HDU - 1560 - DNA sequence,這題估計的是剩餘還需要處理的長度,本題估計的則是剩餘還需要處理的方格(冥冥之中總感覺有相似之處)

估計方格

因為每次輪換,最多隻會引進一個目標元素(直觀感受),因此,還需要處理的方格(即上文需要估計的量),就等於中心元素中,不為目標元素的元素的個數,也就是非目標元素的個數。一旦目標元素確定那計數就小菜一碟啦,但是我們怎麼知道我們的目標是什麼?

目標元素

我的原始思路是,開局在中心元素個數最多的即我們的目標,但是想了想說不定人家也可能一手好牌打得稀爛(結果確實存在這種情況,開始在中間最多的並不是正解),於是我最後決定還是得列舉目標,但是我總感覺開始在中間最多的越有可能是正確答案,於是按照出現的次數排序來進行列舉,搜尋。(但事實證明這並沒有必要,而且寫出來的效果就很讓人懷疑,一個問題居然要搜尋三次)

做完之後我參考了一下其它題解,發現了一種更好的思路。我們完全可以作一棵沒有目標的牆頭草,誰最多我們就往哪倒。也就是說,我們可以計算在中間1,2,3這三個元素的個數的最大值,一旦這個計算結果等於8,我們就完成了任務!這時再去檢查是誰達到了這個數字即可。(另外這樣能夠保證我們的結果就是最優解,按我的原始思路,很有可能出現三組解(一個搜尋一個解),還需要對這三組解進行進一步的比較)

重大問題

  1. cnt()函式——估計哪個數字應該優先搜尋。

在排序時思路不對,導致三個數字不能正常被排序與標記。
(我有時覺得這個函式沒有用,事實上確實沒有用,還徒增很多煩惱)

  1. 搜尋時忘了有H這一操作。。。甚至在很後面才發現。。。

打印出每次的操作,發現只有7種操作,那就可以發現這個bug了,或者是分析出錯的樣例,然後分析為什麼沒有出現某個路徑,然後再定位到拓展葉子節點的程式碼,應該可以發現這個bug

  1. 沒有仔細審題 || 沒有考慮特殊情況——No moves needed

If no moves are needed, output "No moves needed",為什麼說它嚴重呢,因為這將導致對拍完全沒有問題,但是交上去就是WA。-__-
以後做題一定要特例先行!

  1. 沒有意識到1, 2, 3都有可能成為最後的答案,即使某一個數在中心的個數最少。

這個其實反而是最開始的想法,但做著做著題就認為中間數量最多的就是最後答案。。。還是考慮的不夠全面啊

  1. 最後的判斷依據

接著第四點,由於任何一個數都有可能成為答案,最後的判斷依據應該是在某個深度下,誰的操作路徑字典序最小。並且,這裡面還要考慮到如果一個路徑不存在,它的長度可能是最小的(string,長度為0)判斷完之後,最後還得輸出中心元素,這兩個操作如何協調,也是一個麻煩的問題。

  1. 嘗試用map儲存狀態

這會導致TLE==,感覺可能是狀態太多了,希望以後的自己能對這個問題有更多理解,最好還能提出解決的辦法。

  1. 程式碼十分冗雜,同時時間開銷非常大,一定要學習優秀的程式碼

我的思路從一開始就不太正確,以至於後面花費了相當多的精力去給它修修補補。導致了這種情況的發生。

一點感悟

方向錯誤也不是第一次了,每當出現這種情況,我就會想起托勒密,他窮盡他的心血將地心說完善得幾乎完美,但終究在一開始他便錯了。但是他的錯誤也給後人帶來的啟示與借鑑,我也希望我的每一次錯誤都能夠給日後的我或看到這篇文章的人們提供一種資訊,某條路是不行的,幫助他們少走彎路,以上。