Today, I spent some time studying dancing links. The core idea is to reduce the search scope and complexity. The method of reduction is to remove unnecessary vertices in the graph constructed using a chain structure. If it is traced back and then restored.
The data structure that this method relies on is the cross linked list l [NN], R [NN], U [NN], d [NN] Left and Right links stored in arrays.
Construct a Data Structure:
head,cnt,L[NN],R[NN],U[NN],D[NN],H[NN],COL[NN],S[NN],ROW[NN]
The head is the header node, and the CNT is the node number in the graph. s [NN] is the number of elements in a column, Col [NN], row [NN] is the number of rows and columns corresponding to a vertex. H [NN] is the first node number of a row in the graph.
This is the main data structure. Next, let's look at the code.
#define head 100int U[N],D[N],L[N],R[N];int C[N],H[N],ans[N];//C[N]表示N的列标,H[N]表示N的行标,ans[]用来储存结果bool dance(int k){ int c = R[head]; if(c==head) { Output();//Output the solution return true; } remove(c); for(int i=D[c]; i!=c; i=D[i]) { ans[k] = H[i]; for(int j=R[i]; j!=i; j=R[j]) remove(C[j]); if(dance(k+1)) return true; for(int j=L[i]; j!=i; j=L[j]) resume(C[j]);//这里原因和resume中的一样 } resume(c); return false;}void remove(int c){ L[R[c]] = L[c]; R[L[c]] = R[c]; for(int i=D[c]; i!=c; i=D[i]) { for(int j=R[i]; j!=i; j=R[j]) { U[D[j]] = U[j]; D[U[j]] = D[j]; } }}/*resume还有另一种写法,就是将L,R的改变放在最后,循环中U,D调换位置。这其实没什么影响因为L,R都是一条语句不影响其他U,D都是单个操作,而外层循环必须是U的循环,即一个个拿下来在按顺序放回去,不然会错误,自己用纸试一下*/void resume(int c){ L[R[c]] = c; R[L[c]] = c; for(int i=U[c]; i!=c; i=U[i]) { for(int j=R[i]; j!=i; j=R[j]) { U[D[j]] = j; D[U[j]] = j; } }}
The basic operations of the above-mentioned dancing links also involve the diagram. The following uses poj 3740 as an example:
#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int NN=600;int head,cnt,L[NN],R[NN],U[NN],D[NN],H[NN],C[NN],S[NN],ROW[NN];//上下左右 一行的最右,C结点对应的列,S该列的个数int N,M;/*这里插入一个元素,则对竖直方向改变不大 原本的上一个元素的D,表头的U,当前的D指向表头,U指向表头暂存的对于水平方向,注意开头的那个元素的L,前一个元素的R,自己的L=前一个,R=开头。开头标号的暂存在前一个的R中*/void insert(int i,int j){ C[++cnt]=j; S[j]++; D[cnt]=j; U[cnt]=U[j]; if(H[i]){R[cnt]=R[H[i]];L[cnt]=H[i];R[H[i]]=cnt;L[R[cnt]]=cnt;}else R[cnt]=L[cnt]=cnt;D[U[j]]=cnt;U[j]=cnt;H[i]=cnt;}void remove(int c)//删除第c列上的元素所在的行{ R[L[c]]=R[c]; L[R[c]]=L[c]; //删除c,c是列指针,删除了c就代表删除了整列,因为递归后不可能访问到c了 for (int i=D[c]; i!=c; i=D[i]) //c所在列上的元素i for (int j=R[i]; j!=i; j=R[j]) //i和j一行的,删掉j { U[D[j]]=U[j]; D[U[j]]=D[j]; S[C[j]]--;//j所在列的元素(‘1’的个数)-1; }}void resume(int c)//对应的恢复操作{ L[R[c]] = c; R[L[c]] = c; for(int i=U[c]; i!=c; i=U[i]) { for(int j=R[i]; j!=i; j=R[j]) { U[D[j]] = j; D[U[j]] = j; } } }bool dance(){int i,j; if (R[head]==head)//列指针删完了,任务完成 { puts("Yes, I found it"); return true; } int s=0x3fff,c; for ( i=R[head]; i!=head; i=R[i]) if (S[i]<s) s=S[i],c=i; //找元素最少的列c,一种优化 remove(c);//删除列c for ( i=D[c]; i!=c; i=D[i]) { for ( j=R[i]; j!=i; j=R[j]) remove(C[j]);//删除所有可能的冲突元素 if (dance()) return true; for ( j=L[i]; j!=i; j=L[j]) resume(C[j]); } resume(c); return false;}/*初始化注意,由于有head,则构图时下标都从1开始,每个元素都是自然下标cnt的赋值不要忘记*/void init(){int i,j,k;for(i=0;i<=M;i++){L[i+1]=i;R[i]=i+1;U[i]=D[i]=C[i]=i;S[i]=0;}L[0]=M,R[M]=0;cnt=M;for(i=1;i<=N;i++){H[i]=0;for(j=1;j<=M;j++){scanf("%d",&k);if(k)insert(i,j);}}}int main(){ int c,i; head=0; while (~scanf("%d%d",&N,&M)) { init(); if(!dance()) puts("It is impossible");} return 0;}
There is also the original DFS:
#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>#include <math.h>using namespace std;int N,M,T;int maps[20][310];int rows[310];int dfs(int n,int cnt){if(cnt==N) return 1;int i,j,k;for(i=n;i<M;i++){k=cnt;for(j=0;j<N;j++)if(maps[i][j]==1 && rows[j]==1)break;if(j<N)continue;for(j=0;j<N;j++)if(maps[i][j]==1)rows[j]=1,k++;if(dfs(i+1,k))return 1;for(j=0;j<N;j++)if(maps[i][j]==1)rows[j]=0;}return 0;}int main(){ while(scanf("%d%d",&M,&N)!=EOF){int i,j;memset(rows,0,sizeof(rows));memset(maps,0,sizeof(maps));for(i=0;i<M;i++)for(j=0;j<N;j++)scanf("%d",&maps[i][j]);if(dfs(0,0))printf("Yes, I found it\n");elseprintf("It is impossible\n"); } return 0;}
Dancing links learning and code explanation