跳舞链 (DLX)模板。。

 

#define CL(a,num) memset((a),(num),sizeof(a))
#define inf 0x7f7f7f7f
#define M 1007
#define N 1000007

const int head = 0;
int u[N],d[N],l[N],r[N],c[N],row[N];
int s[M],o[M];
int ak,n,m;

void init(int m){
    int i;
    for (i = 1; i <= m; ++i){
        l[i] = i - 1;
        r[i] = i + 1;
        u[i] = d[i] = i;
        c[i] = i;
        s[i] = 0;
    }
    l[head] = m; r[head] = 1;
    r[m] = head;
}

void remove(int ci){
    int i,j;
    l[r[ci]] = l[ci];
    r[l[ci]] = r[ci];

    for (i = d[ci]; i != ci; i = d[i]){
        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 ci){
    int i,j;
    l[r[ci]] = r[l[ci]] = ci;
    for (i = u[ci]; i != ci; i = u[i]){
        for (j = l[i]; j != i; j = l[j]){
            u[d[j]] = d[u[j]] = j;
            s[c[j]]++;
        }
    }
}
int dfs(int k){
    int i,j;
    //若列对象为空,说明所有列已经覆盖,返回值
    if (r[head] == head){
        ak = k;
        return 1;
    }
    //每次着该列里面1最少的
    int MIN = inf, ci = 0;
    for (i = r[head]; i != head; i = r[i]){
        if (s[i] < MIN){
            MIN = s[i];
            ci = i;
        }
    }
    remove(ci);//删除该列对象以及该列所覆盖的行
    for (i = d[ci]; i != ci; i = d[i]){
        for (j = r[i]; j != i; j = r[j]){
            remove(c[j]);//选择i作为覆盖c列的行,并且要删调该行所覆盖的列
        }
        o[k] = row[i];//记录结果
        if (dfs(k + 1)) return 1;//继续选择列

    //i列不能满足还原i列
        for (j = l[i]; j != i; j = l[j]){
            resume(c[j]);
        }
    }
    resume(ci);
    return 0;
}
int main(){
    int i,j;
    int num,size;
    while (~scanf("%d%d",&n,&m)){
      //更新列对象
       init(m);
        size = m + 1;//记录第几个
        int x;
        for (i = 0; i < n; ++i){
            scanf("%d",&num);
            int rh = -1;
            for (j = 0; j < num; ++j){
                scanf("%d",&x);

                s[x]++;//记录x列有多少个1
                c[size] = x;//记录第size个的列
                row[size] = i + 1;//记录第size个的行
        //插入列,挂链
                u[size] = u[x];
                d[u[x]] = size;
                u[x] = size;
                d[size] = x;

        //插入行,挂链
                if (rh == -1){
                    l[size] = r[size] = size;
                    rh = size;
                }
                else{
                    l[size] = l[rh];
                    r[l[rh]] = size;
                    l[rh] = size;
                    r[size] = rh;
                }
                size++;
            }
        }
        if (dfs(0)){
            printf("%d",ak);
            for (i = 0; i < ak; ++i) printf(" %d",o[i]);
            printf("\n");
        }
        else{
            printf("NO\n");
        }
    }
    return 0;
}

  




http://blog.csdn.net/mu399/article/details/7627736
  
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值