HUST 1017 Exact cover 跳舞链(DLX) 模板题目

http://acm.hust.edu.cn:8080/judge/problem/viewProblem.action?id=10702

题意:

给你一个n*m的01矩阵,让你选择若干行使这些行中的1能够覆盖所有的列,而且不能出现重复覆盖。输出所选的行。

思路:

这是跳舞链的模板题目。不多说了。

给出个人觉得讲解比较好的链接:http://blog.csdn.net/mu399/article/details/7627736

参考代码:http://blog.csdn.net/dooder_daodao/article/details/6654904

 

我的代码:

View Code
#include <cstdio>

#include <cstring>

#include <iostream>





using namespace std;



#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;

}

 

 

 

你可能感兴趣的:(over)