dancing links X算法

来源:互联网 发布:网络英雄洛克人 ed2k 编辑:程序博客网 时间:2024/06/10 06:38

hust 1017Exact cover

就是knuth论文里拿来举例子的题, 算是精确覆盖的裸题了。


#include <cstdio>#include <cstring>/** 在01矩阵找一个行集合,使其精确覆盖所有的列所谓精确覆盖就是所有行中含1的列有且仅有一个,而重复覆盖允许有多个。**/const int maxn=100000+123;const int maxc=1000+5;int S[maxc], L[maxn], R[maxn], D[maxn], U[maxn];int H[maxc], ok[maxc], sz, C[maxn], mark[maxn];///H是横向的表头, 不知道必不必要void Link(int row, int col){    S[col]++; C[sz]=col;///C域指向列头    U[sz]=U[col]; D[U[col]]=sz;    D[sz]=col; U[col]=sz;        if(H[row]==-1)H[row]=L[sz]=R[sz]=sz;    else    {        L[sz]=L[H[row]]; R[L[H[row]]]=sz;        R[sz]=H[row]; L[H[row]]=sz;    }    mark[sz]=row;/// 标记每个点是哪一行(题目要求输出解属于哪一行)    sz++;}void remove(int col){    L[R[col]]=L[col];    R[L[col]]=R[col]; /// 在列对象链表中删除col    for (int i=D[col]; i!=col; i=D[i])    {/// 删除col列中有1元素的行        for (int j=R[i]; j!=i; j=R[j])        {///删除每行的1元素,并修改所在列的S域            U[D[j]]=U[j], D[U[j]]=D[j];            S[C[j]]--;        }    }}void resume(int col){    for (int i=U[col]; i!=col; i=U[i])    {        for (int j=L[i]; j!=i; j=L[j])        {            U[D[j]]=j; D[U[j]]=j;            S[C[j]]++;        }///恢复删除的元素,恢复S域    }///恢复删除的行    L[R[col]]=col;    R[L[col]]=col;}bool Dance(int k){    //printf("%d\n", k);    if(R[0]==0)    {        printf("%d", k);        for (int i=0; i<k; ++i)            printf(" %d", ok[i]);        puts("");        return true;    }    int c=R[0];    for(int i=R[0]; i; i=R[i])        if(S[i]<S[c])c=i;    remove(c);//    printf("remove col %d\n", c);    for(int i=D[c]; i!=c; i=D[i])    {        ok[k]=mark[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(c);    return false;}void initL(int x){    for (int i=0; i<=x; ++i)///i<x???    {        S[i]=0;        D[i]=U[i]=i;        L[i+1]=i; R[i]=i+1;    }///对列表头初始化    R[x]=0;    sz=x+1;///真正的元素从m+1开始    memset (H, -1, sizeof(H));    ///mark每个位置的名字}int main(){    int n, m;     while(~scanf("%d%d", &n, &m))    {        initL(m);        for (int i=1; i<=n; ++i)        {            int k; scanf("%d", &k);            while (k--)            {                int x; scanf("%d", &x);                Link(i, x);            }        }        if(!Dance(0))puts("NO");    }    return 0;}


原创粉丝点击