DLX學習筆記

2022-09-19 12:24:11 字數 2972 閱讀 9170

\(\text\),舞蹈鏈,主要解決精確覆蓋問題和重複覆蓋問題。

本文暫時只介紹精確覆蓋問題。

重複覆蓋問題不知什麼時候再更。

p4929 【模板】舞蹈鏈(dlx)

題意:給定乙個 \(n\) 行 \(m\) 列的矩陣,矩陣中每個元素要麼是1,要麼是0

你需要在矩陣中挑選出若干行,使得對於矩陣的每一列 \(j\) ,在你挑選的這些行中,有且僅有一行的第 \(j\) 個元素為 \(1\)。

大致思路

大致將這一類問題總結成了幾個步驟。

建模,將問題轉換成如上題的模板。

開始寫板子。

而板子大致又分成如下幾個步驟:

將用十字鍊錶的圖建出來。

選中一行,將其中有一的每一列標記出來。

再將標記出的每一列中有一的那一行標記出來。

將所有標記的刪掉,合成新矩陣。

若新矩陣不為空,則重複上述步驟;若為空,判斷之前是否全為一,若是,則有解,否則無解。

現在應該比較清晰了吧。

#include using namespace std;

const int maxn = 6000;

int n , m , tot , cnt;

int l[maxn] , r[maxn] , d[maxn] , u[maxn];

int qx[maxn] , qy[maxn] , vy[maxn] , ans[maxn];

inline int read()

inline void init()

r[m] = 0 , l[0] = m;

cnt = m + 1;

}inline void add(int &ll , int &rr , int x , int y)

inline void remove(int p)

return;

}inline void resume(int p)

l[r[p]] = r[l[p]] = p;

return;

}inline bool dfs()

resume(p);

return false;

}int main()

}if(dfs())

for(int i = 1;i <= tot;i++) cout << ans[i] << " ";

else

cout << "no solution!";

return 0;

}

生為乙個懶人,這就是最後一題了。

sp13980 sudogob - sudoku goblin

一道顯然的 \(\text\) 模板題。

這裡注重講一下如何建模。

首先考慮乙個數獨,需要滿足的條件。

注意最後乙個情況,這是最容易遺漏的乙個情況。

根據 \(\text\) 性質,我們不妨將每一種情況設為每一行,而每乙個限制設為每一列,就建出了模型。

考慮每一種情況

我們讓 \(a_\) 為第 \(i\) 行,第 \(j\) 列上的數。

那麼這個位置九個數都有可能被填,那麼就都需要加上去。

那麼這個位置就只有唯一的解法。

考慮每一種限制

對於之前的情況,我們需要在不同的列中,根據限制加點。

由於有四個限制,我們可以加四個點。

**大致如下:

add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 0 + (i - 1) * 9 + j);

add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 1 + (i - 1) * 9 + k);

add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 2 + (j - 1) * 9 + k);

add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 3 + ((i - 1) / 3 * 3 + (j - 1) / 3) * 9 + k);

其餘的就可以直接寫板子了。

#include using namespace std;

const int maxn = 5000;

int n , m , t , sum , cnt , tot , a[15][15];

int l[maxn] , r[maxn] , u[maxn] , d[maxn] , h[maxn] , qx[maxn] , qy[maxn] , vy[maxn] , ans[maxn];

inline int read()

inline void init()

tot = 0 , cnt = m + 1 , l[0] = m , r[m] = 0;

memset(vy , 0 , sizeof(vy));

memset(qx , 0 , sizeof(qx));

memset(qy , 0 , sizeof(qy));

memset(ans , 0 , sizeof(ans));

}inline void add(int x , int y)

inline void remove(int p)

return;

}inline void resume(int p)

l[r[p]] = r[l[p]] = p;

return;

}inline void dfs()

int p = r[0];

for(int i = r[0];i;i = r[i])

if(vy[p] > vy[i]) p = i;

remove(p);

for(int i = d[p];i != p;i = d[i])

resume(p);

}int main()}}

}dfs();

cout << sum << endl;

if(sum == 1)}}

return 0;

}

DLX 精確覆蓋問題

精確覆蓋問題 給定乙個由0 1組成的矩陣,問是否能找到乙個行的集合,使得集合中每一列都恰好包含乙個1 如圖 演算法x 通過dfs,每次選取一行可行 模擬演算法x過程 很容易想到上面的搜尋,但是狀態的改變很難操作,包括了刪除和復原,使用普通的資料結構運算根本停不下來。於是,一位大師想到了神奇的資料結構...

DLX演算法合集 I

dlx是一種相當神奇的資料結構,通常用於解決矩陣 多為稀疏矩陣 的 重複 精確 覆蓋的問題。不過一般這類問題的難點是抽出轉化關係,剩下的幾乎就是套模板 include include include include include include includeusing namespace std...

DLX 精確覆蓋 重複覆蓋

給定乙個n m的矩陣,有些位置為1,有些位置為0。如果g i j 1則說明i行可以覆蓋j列。problem 1 選定最少的行,使得每列有且僅有乙個1.2 選定最少的行,使得每列至少乙個1.這類屬於np問題的問題,可以使用搜尋解決。但是普通的搜尋必超時無疑。因此我們要設法加優化來加快速度。dancin...