166. 數獨 dancing links 方法

dfs硬懟經過數獨 N皇后的代碼後 想學習下新的數據結構和算法來解決這類覆蓋問題html

習題練習node

https://www.acwing.com/problem/content/168/ 數獨ios

https://www.acwing.com/problem/content/171/ 數獨2算法

https://www.acwing.com/problem/content/185/ 靶形數獨數組

資料收集以下 進行學習數據結構

http://www.javashuo.com/article/p-kqgjimbg-g.html數據結構和算法

http://www.javashuo.com/article/p-xvtetkog-u.htmlide

https://blog.csdn.net/whereisherofrom/article/details/79220897函數

 

習題學習學習

洛谷 

https://www.luogu.org/problem/P4929  P4929 【模板】舞蹈鏈(DLX)

https://www.luogu.org/problem/P1074  P1074 靶形數獨

https://www.luogu.org/problem/P1219  P1219 八皇后

題解 

https://www.luogu.org/blog/ONE-PIECE/qian-tan-dlx  【模板】舞蹈鏈(DLX)

https://www.luogu.org/blog/ONE-PIECE/ba-xing-shuo-du-dai-ma  靶形數獨

https://www.luogu.org/blog/ONE-PIECE/solution-p1219 八皇后

 

 

個人對模板註釋的代碼  參考的源代碼地址https://www.luogu.org/blog/ONE-PIECE/qian-tan-dlx 

  1 #include <iostream>  
  2 #include <stdio.h>  
  3 #include <string.h>  
  4 
  5 
  6 //精確覆蓋問題的定義:給定一個由0-1組成的矩陣,是否能找到一個行的集合,使得集合中每一列都剛好包含一個1
  7 const int MN = 9 * 9 * 9 + 10;//最大行數,共有9*9個格子,每一個格子能夠放1~9
  8 const int MM = 9 * 9 + 9 * 9 + 9 * 9 + 9 * 9 + 100;//最大列數
  9 const int MAX_NUM = MN * MM; //最大點數  
 10 
 11 struct DLX
 12 {
 13     int n, m, idx;//n行數m列數idx 元素索引 
 14                  //十字鏈表組成部分  
 15 
 16     int l[MAX_NUM], r[MAX_NUM], u[MAX_NUM], d[MAX_NUM];    //記錄某個idx索引點的上下左右點的索引
 17     int col[MAX_NUM], row[MAX_NUM];    //二者結合使用 記錄某個idx索引點的行 列號
 18 
 19 
 20     int nodeIdxPerRow[MAX_NUM];        //記錄每行的開頭節點的索引
 21     int nodeNumPerCol[MAX_NUM];        //記錄每列節點的個數
 22 
 23 
 24     int ansd, ans[MN];
 25 
 26     void init(int n ,int m)    //初始化十字鏈表的 頭節點和 列節點表頭串   m表示有多少列
 27     {
 28         //初始化頭結點和 列節點表頭串 頭節點數組索引 = 0  列節點表頭共m個 索引 1~m
 29         for (int i = 0; i <= m; i++) {
 30             r[i] = i + 1;
 31             l[i] = i - 1;
 32             u[i] = d[i] = i;    //列節點頭串只有互相橫向鏈接 上下鏈接均指向本身
 33         }
 34         r[m] = 0;
 35         l[0] = m;  //循環鏈接 col[m] 的右端指向頭節點 頭結點的左端指向clo[m]
 36 
 37         memset(nodeIdxPerRow, 0, sizeof(nodeIdxPerRow));
 38         memset(nodeNumPerCol, 0, sizeof(nodeNumPerCol));
 39 
 40         idx = m + 1; //目前使用 0 頭結點 與 m個列節點表頭串 0~m 共m+1個節點     
 41     }
 42 
 43 
 44 
 45     //插入節點 進行的一些數據記錄  
 46     void link(int insertRow, int insertCol)
 47     {
 48         nodeNumPerCol[insertCol]++; //插入一個節點 那麼該列的節點個數+1
 49         row[idx] = insertRow;
 50         col[idx] = insertCol;    //記錄第idx個節點所在的行與列
 51 
 52         u[idx] = insertCol;    //當前插入的節點索引記錄 向上指向列節點頭串中的insertCol
 53         d[idx] = d[insertCol];    //當前插入節點索引記錄 向下指向原來列節點頭串的向下指向點
 54         u[d[insertCol]] = idx;    //原來列節點頭串指向的節點 向上由指向列節點頭串指向插入的節點(使用索引)
 55         d[insertCol] = idx;        //列節點頭串則向下指向新插入的節點(使用索引)
 56 
 57         //更新每行的節點記錄  nodeIdxPerRow
 58         if (nodeIdxPerRow[insertRow] == 0) {
 59             //若是該節點是第一個插入的節點
 60             nodeIdxPerRow[insertRow] = r[idx] = l[idx] = idx;//該行沒有點,直接加入 
 61         }
 62         else {
 63             //若是不是第一個插入的節點 同上面處理列次序同樣 在記錄和第一個節點間 插入本函數插入的節點
 64             r[idx] = nodeIdxPerRow[insertRow];        //新節點的右端指向原來行記錄中的第一個節點
 65             l[idx] = l[nodeIdxPerRow[insertRow]];    //新節點的左端指向原來行記錄第一個節點的左端 也就是行記錄nodeIdxPerRow
 66             r[l[nodeIdxPerRow[insertRow]]] = idx;    //原來行記錄第一個節點的左端(也就是行記錄nodeIdxPerRow)的右端 指向新插入的點(使用索引)
 67             l[nodeIdxPerRow[insertRow]] = idx;        //原來行記錄第一個節點的左端指向新插入的節點(使用索引)
 68 
 69         }
 70         idx++;
 71         return;
 72     }
 73 
 74     void remove(int deleteCol) {//刪除涉及C列的集合 
 75      //將要刪除的列的左右兩端鏈接起來 也等於將本身摘除出來
 76         r[l[deleteCol]] = r[deleteCol], l[r[deleteCol]] = l[deleteCol];
 77         for (int i = d[deleteCol]; i != deleteCol; i = d[i]) {
 78             for (int j = r[i]; j != i; j = r[j]) {
 79                 u[d[j]] = u[j];
 80                 d[u[j]] = d[j];
 81                 nodeNumPerCol[col[j]]--;
 82             }
 83         }
 84     }
 85     void resume(int resCol) {//恢復涉及C列的集合 
 86         for (int i = u[resCol]; i != resCol; i = u[i]) {
 87             for (int j = l[i]; j != i; j = l[j]) {
 88                 u[d[j]] = j;
 89                 d[u[j]] = j;
 90                 nodeNumPerCol[col[j]]++;
 91             }
 92         }
 93         r[l[resCol]] = resCol;
 94         l[r[resCol]] = resCol;
 95     }
 96 
 97     
 98 
 99     bool dance(int deep) //選取了d行  
100     {
101         if (r[0] == 0)//所有覆蓋了  
102         {
103             //全覆蓋了以後的操做  
104             ansd = deep;
105             return 1;
106         }
107 
108 
109         int c = r[0];//表頭結點指向的第一個列
110         for (int i = r[0]; i != 0; i = r[i])//枚舉列頭指針
111         {
112             if (nodeNumPerCol[i] < nodeNumPerCol[c])c = i;
113 
114         }
115 
116         remove(c);//將該列刪去
117         for (int i = d[c]; i != c; i = d[i])
118         {//枚舉該列的元素
119             ans[deep] = row[i];//記錄該列元素的行
120             for (int j = r[i]; j != i; j = r[j])
121                 remove(col[j]);//將該列的某個元素的行上的元素所在的列都刪去
122             if (dance(deep + 1))
123                 return 1;
124             for (int j = l[i]; j != i; j = l[j])
125                 resume(col[j]);
126         }
127         resume(c);
128         return 0;
129     }
130 }dlx;
131 //==========================================================
132 
133 
134 char s[90], path[90];
135 struct node
136 {
137     int r, c, v;
138 }nds[MN];
139 int main()
140 {
141     while (~scanf("%s", s))
142     {
143         if (s[0] == 'e')break;
144         dlx.init(9 * 9 * 9, 9 * 9 * 4);
145         int r = 1;
146         for (int i = 1; i <= 9; i++)
147         {
148             for (int j = 1; j <= 9; j++)
149             {
150                 if (s[(i - 1) * 9 + j - 1] == '.')
151                 {
152                     for (int z = 1; z <= 9; z++)
153                     {
154                         dlx.link(r, (i - 1) * 9 + j);
155                         dlx.link(r, 81 + (i - 1) * 9 + z);
156                         dlx.link(r, 162 + (j - 1) * 9 + z);
157                         dlx.link(r, 243 + (((i - 1) / 3) * 3 + (j + 2) / 3 - 1) * 9 + z);
158                         nds[r].r = i, nds[r].c = j, nds[r].v = z;
159                         r++;
160                     }
161                 }
162                 else
163                 {
164                     int z = s[(i - 1) * 9 + j - 1] - '0';
165                     dlx.link(r, (i - 1) * 9 + j);
166                     dlx.link(r, 81 + (i - 1) * 9 + z);
167                     dlx.link(r, 162 + (j - 1) * 9 + z);
168                     dlx.link(r, 243 + (((i - 1) / 3) * 3 + (j + 2) / 3 - 1) * 9 + z);
169                     nds[r].r = i, nds[r].c = j, nds[r].v = z;
170                     r++;
171                 }
172             }
173         }
174         dlx.ansd = -1;
175         dlx.dance(0);
176         int deep = dlx.ansd;
177         for (int i = 0; i < deep; i++)
178         {
179             int posr = dlx.ans[i];
180             path[(nds[posr].r - 1) * 9 + nds[posr].c - 1] = '0' + nds[posr].v;
181         }
182         path[deep] = '\0';
183         printf("%s\n", path);
184     }
185     return 0;
186 }
View Code
相關文章
相關標籤/搜索