对于Dancing Links X算法接精确覆盖的解释
之前写的hust1017精确覆盖的代码,鉴于有的同学可能不是很了解其性能,所以对之前的代码进行展开解释。
const int N = 1100 , V = 102020; int U[V] , D[V] , L[V] , R[V] , C[V]; int H[N] , S[N] , mark[V]; int size , n , m , OK[N] , flag; void Link(int r,int c) {Link(r,c)表示在第r行第c列插入一个“1”元素 S[c] ++; C[size] = c; //C[size]表示第size个元素所在的列 U[size] = U[c]; D[U[c]] = size; D[size] = c; U[c] = size; //这四步表示把size插入到U[c]和c之间 if(H[r] == -1) H[r]=L[size]=R[size]=size; //如果第r列之前为空,则size的左右指针均指向本身 else { L[size]=L[H[r]];R[L[H[r]]]=size; R[size]=H[r];L[H[r]]=size; //这四步表示把size插入道L[H[r]]和H[r]之间 } mark[size] = r; //mark[size]表示第size个元素所在的行 size ++; //size表示0-1矩阵中“1”元素的个数 } void remove(int c) { //delete column删除第c列 int i , j; L[R[c]] = L[c]; R[L[c]] = R[c]; // 删除第c列的头指针 for(i=D[c];i!=c;i=D[i]) { //将第c列含“1”的元素对应的行业删除 for(j=R[i];j!=i;j=R[j]) { U[D[j]] = U[j]; D[U[j]] = D[j]; S[C[j]] --; } } } void resume(int c) { //回复的时候过程与删除的时候相反 int i , j; for(i=U[c];i!=c;i=U[i]) { for(j=L[i];j!=i;j=L[j]) { U[D[j]] = j; D[U[j]] = j; S[C[j]] ++; } } L[R[c]] = c; R[L[c]] = c; } void Dance(int k) { //进行搜索 int i , j ,Min , c; if(!R[0]) { flag = 1; printf("%d",k); for(i=0;i<k;i++) printf(" %d",mark[OK[i]]); printf("\n"); return; } for(Min=N,i=R[0];i;i=R[i]) if(S[i] < Min) Min = S[i] , c = i; remove(c); for(i=D[c];i!=c;i=D[i]) { OK[k] = i; //remove(i); for(j=R[i];j!=i;j=R[j]) remove(C[j]); Dance(k+1); if(flag) return; for(j=L[i];j!=i;j=L[j]) resume(C[j]); //resume(i); } resume(c); } int main() { int i , j , num; while(~scanf("%d%d",&n,&m)) { for(i=0;i<=m;i++) { S[i] = 0; D[i] = U[i] = i; L[i+1] = i; R[i] = i + 1; } R[m] = 0; size = m + 1; memset(H,-1,sizeof(H)); memset(mark,0,sizeof(mark)); for(i=1;i<=n;i++) { scanf("%d",&num); while(num --) { scanf("%d",&j); Link(i , j); } } flag = 0; Dance(0); if(!flag) puts("NO"); } return 0; }