舞蹈鍊 Dancing Link(DLX)
寫數獨的時候,我發現除了DFS遞迴剪枝還有另一中更快的酷做法,但當時沉浸在AC的喜悅中就沒有學,後來在洛谷河道剛好逛到這東東,才學會這酷酷演算法(但我太笨畫很久才學會)
*本篇文章大量參考這裡,因為是我學的地方,非常感謝作者大佬
- 舞蹈鍊是幹嘛的
舞蹈鍊最主要解決的問題是精確覆蓋問題,在各個子集合中選擇若干個使其包含整個全集,並且各個子集合不重疊
,上維基百科,畫個圖就是這樣
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
要選擇其中幾行,使每一列都有一個,並且選擇的行中,有的列不能重疊
模板題
X algorithm 舞蹈鍊的靈魂
這個問題解決的方法呢,就是暴力遞迴枚舉,具體過程如下:
- 如果只剩一個集合(行),並且所有元素都是 ,代表找到解了,否則去
- 選擇一個集合(行),把其中覆蓋到的列刪除,包括重疊到的集合(行)
- 如果此時剩下一個集合(行),回到 ,否則回到
- 如果只剩一個集合(行),且其中有元素是 代表先前選擇的集合有錯誤,回溯後繼續
畫個圖流程大概是這樣:
- 先選擇集合(1.),把重疊到的 (藍色) 和其 (黃色) 所在集合 (紫色) 都刪掉
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
- 把有顏色的拿掉變成這樣,只剩(3.)集合,但裡面有,回溯到上一步
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
- 選擇集合(2.),一樣把重複到的刪掉
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
- 剩下集合(3.)且沒有,找到解是 : 集合(2.)和(3.)
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
雖然我圖畫得很亂可能不太好懂qwq,但看懂後可以發現,演算法最大的問題在於,要怎麼實現刪除行,回溯後還要恢復,顯然這用二維陣列來處理不只難寫而且時空複雜度也會極高。
那有什麼資料結構可以支持快速刪除和恢復呢? linked-list
!
Dacing Link 舞蹈鍊
先來複習一下linked-list
要怎麼刪除和恢復
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
假設我想刪除節點,只要改變一下和的指標就好,相當於節點消失了
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
不過仔細看看節點,雖然他已經不在linked-list
上了,但他的節點本身還是存在,且指標也還指向linked-list
,所以我們可以透過這個特性恢復
回到Dacing Link
本身,他是一個十字鍊,長這樣
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
其實他是一個循環鍊,也就是頭尾會相連,但太麻煩了我懶的畫。因為這些特性,他有一個非常強大的名字,十字交叉雙向循環鍊表,好但沒人會這樣叫他,我也叫他舞蹈鍊。
那怎麼建圖(鍊?)呢? 把上面的矩陣中的變成一個節點,則讓他空著,像這樣
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
好亂,而且怎麼跑出一堆奇怪的節點了?
- head節點 : 用途是方便我們確認答案,只是一個輔助節點
- 列節點 : 也是用判斷答案的輔助節點
- 行編號 : 集合的編號,只是畫出來比較好理解,不是一個真實的節點
有了這個資料結構,再把上面X algorithm的執行過程搬過來,你就會DLX了!
- 如果沒有任何集合(行)存在,判斷還有沒有列節點(
head.r==head
),沒有就是找到答案了
- 如果還有集合(行),選擇其中一個,把覆蓋到的、重複的等等節點刪除
- 如果刪完沒有集合了,回到 ,否則回到
- 如果沒有任何集合存在,且還有列節點存在(
head.r!=head
),代表之前的決策有錯誤或根本無解,回溯並繼續遞迴枚舉
選擇(1.)集合,把覆蓋到的和其所在的集合刪除
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
所有集合都消失了,但還有列節點,要回溯繼續求解
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
選擇集合(2.),一樣刪除該刪除的節點,(這裡列節點應該是藍色,我畫錯了qwq)
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
還有集合,繼續選擇(3.)集合
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
沒有集合了,且列節點全空,找到答案了
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
忍受一下我畫的醜圖,消化一下,再來直接上程式
DLX實作
題目以上面的模板題做舉例
nd
是存節點的結構體,dl
是節點的陣列,ans
紀錄最後答案,row
紀錄每一行(集合)的第一個節點,sz
是每一列下面有多少個節點(可以不用,用於優化),n
跟m
是題目的定義,cnt
用於加點
先處理好所有列節點,上下因為都沒有節點,所以指向自己,左右與相鄰的列節點形成環,其中dl[0]
是head
節點,至於row
也就是行可以先不處理,因為他不是真實的點。
處理完圖會長這樣子
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
r
和c
是在第幾行第幾列增加節點,先把上下連好,上個圖應該比較清楚
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
再來就處理左右的指標,要判斷他是不是這行的第一個節點,方便更新row
陣列,應該不難理解,這裡就不上圖了因為我懶,如果真的不行可以自己畫畫看
最前面把這列的列節點從列的linked-list
裡刪除,等同於刪除了這一列,但我們還要去枚舉刪除同在這一列的集合(行),因為不能重複覆蓋,只刪除上下指標,代表從候選集合中刪除,但還是保留左右指標,確保同一集合連在一起,以便後續回溯復原

畫的有點超亂,希望看得懂
就完全是刪除的反動作,枚舉所有因為這一列被刪除的集合,上下關係連回來,最後復原這一列的列節點,具體原理上面linked-list
的復原有講到(雖然帶過而已),思考一下會發現刪除跟復原的順序很巧妙。
- 最後是Dacing Link的靈魂 跳舞(X algorithm)
先判斷是不是找到解了(head.r==head)
,是的話輸出答案,不然繼續遞迴。選擇其中一列(sz
的優化就在這,在洛谷會TLE
,吸沒吸氧都一樣)這裡選擇節點最少的列,然後刪除,再去枚舉要選擇這一列的哪個集合,集合中所有節點所在的列刪除後遞迴下去,回溯時復原,回傳1
代表找到解了,0
代表還沒。
那重要的部分都講完了,整段程式在這,main()
應該都看得懂,就不多說了
雜
看完後你可能會好奇時間複雜度? 我可以很不負責任的告訴你,我不知道,我有去找過,但每個地方說的都不一樣,我也不是證明大師,就不亂下定義了,畢竟他是遞迴枚舉,複雜度不好估算,只能等你各位大佬證明了。
至於DLX可以在甚麼場景應用? 我目前聽過數獨,八皇后等等遞迴枚舉的地方,其實只要想辦法把問題轉成精確覆蓋問題就能使用DLX,這點也是DLX最難的地方(畢竟他算是模板),更多應用也得你各位大佬證明。
我只是個甚麼都不會的競程蒟蒻,如果這篇沒辦法讓你看懂我很抱歉qwq,那推我學的地方,如果這篇文章有任何問題,歡迎來我的DC提出(沒有問題也可以來找我聊天)