刚看了DLX,找到hust1017练了一下
为什么叫dancing links呢,据说是因为算法的创造者knuth感觉这个算法太妙了,不尽让人想起美丽的舞蹈,于是就有了这个名字。的确,DLX对搜索的优化让人叹为观止,缩小稀疏图,减小搜索范围,同时能很快的恢复图的构建,非常妙!
momodi 的论文《Dancing Links 在搜索中的应用》 还有原著的英文论文,看看很不错
跳舞链采用的是十字双向循环链表的数据结构,这种结构很容易实现删除和恢复操作。
//实现删除操作
L[R[c]] = L[c];
R[L[c]] = R[c];
//实现恢复操作
U[D[j]] = j;
D[U[j]] = j;
DLX是为了解决精确覆盖问题而设计
精确覆盖问题可以描述为:给定一个01矩阵, 现在要选择一些行,使得每一列有且仅有一个1
删除的过程可以看作是:
找到节点最少的列c,对于所有map[i][c] == 1的行进行删除
对于找到的第i行,对于所有map[i][j] == 1的第j列进行同样的删除操作
代码
1 #include<stdio.h>
2 #include<string.h>
3 #define INF 0x3fffffff
4 #define NN 1004
5 int N, M;
6 int row[NN][NN];
7 int col[NN][NN];
8 int cntr[NN];
9 int cntc[NN];
10 int L[NN * NN], R[NN * NN], U[NN * NN], D[NN * NN], C[NN * NN];
11 int O[NN];
12 int idx, head;
13
14 /*删除第c列*/
15 void remove(int c){
16 L[R[c]] = L[c];
17 R[L[c]] = R[c];
18
19 int i, j;
20 for (i = D[c]; i != c; i = D[i]){
21 for (j = R[i]; j != i; j = R[j]){
22 U[D[j]] = U[j];
23 D[U[j]] = D[j];
24 cntc[C[j]]--;
25 }
26 }
27 }
28 /*恢复第c列*/
29 void resume(int c){
30 L[R[c]] = c;
31 R[L[c]] = c;
32
33 int i, j;
34 for (i = D[c]; i != c; i = D[i]){
35 for (j = R[i]; j != i; j = R[j]){
36 U[D[j]] = j;
37 D[U[j]] = j;
38 cntc[C[j]]++;
39 }
40 }
41 }
42 int dfs(){
43
44 if (R[head] == head) return 1;
45
46 int min = INF;
47 int c, i, j;
48 for (i = R[head]; i != head; i = R[i]){
49 if (cntc[i] < min){
50 c = i;
51 min = cntc[i];
52 }
53 }
54 remove(c);
55 for (i = D[c]; i != c; i = D[i]){
56 O[idx++] = (i - 1) / M;
57 for (j = R[i]; j != i; j = R[j]){
58 remove(C[j]);
59 }
60 if (dfs()) return 1;
61 /*这个顺序很重要,删除和恢复的方向必须相反
62 开始相同,都是向右的,结果TLE了*/
63 for (j = L[i]; j != i; j = L[j]){
64 resume(C[j]);
65 }
66 idx--;
67 }
68 resume(c);
69 return 0;
70 }
71
72 int Build(){
73 int i, j;
74 head = 0;
75 for (i = 0; i < M; i++){
76 R[i] = i + 1;
77 L[i + 1] = i;
78 }
79 R[i] = 0;
80 L[0] = i;
81
82 for (i = 1; i <= N; i++){
83 for (j = 1; j < cntr[i]; j++){
84 R[row[i][j]] = row[i][j + 1];
85 L[row[i][j + 1]] = row[i][j];
86 }
87 R[row[i][j]] = row[i][1];
88 L[row[i][1]] = row[i][j];
89 }
90 for (i = 1; i <= M; i++){
91 for (j = 1; j < cntc[i]; j++){
92 D[col[i][j]] = col[i][j + 1];
93 U[col[i][j + 1]] = col[i][j];//写成row了
94 }
95 D[col[i][j]] = i;
96 D[i] = col[i][1];
97 U[i] = col[i][j];
98 U[col[i][1]] = i;
99 if (cntc[i] == 0) return 0;
100 }
101 return 1;
102 }
103 int main()
104 {
105 int i, j, tmp, a;
106 while(scanf("%d%d", &N, &M) != EOF){
107 //memset(cntr, 0, sizeof(cntr));
108 //memset(cntc, 0, sizeof(cntc));
109 for (i = 1; i <= M; i++) cntc[i] = 0;
110 for (i = 1; i <= N; i++){
111 scanf("%d", &cntr[i]);
112 for (j = 1; j <= cntr[i]; j++){
113 scanf("%d", &tmp);
114 row[i][j] = tmp + i * M;
115 cntc[tmp]++;
116 col[tmp][cntc[tmp]] = tmp + i * M;
117 C[tmp + i * M] = tmp;
118 }
119 }
120 if (Build()){
121 idx = 0;
122 if (dfs()){
123 printf("%d", idx);
124 for (i = 0; i < idx; i++) printf(" %d", O[i]);
125 puts("");
126 }else puts("NO");
127 }else puts("NO");
128 }
129 return 0;
130 }
131
傻崽大牛详解:A Crazy Man