HUST 1017 Exact cover

来源:互联网 发布:网络学历教育报名 编辑:程序博客网 时间:2024/05/20 02:54

题目大意:给出一个01矩阵,让你选出几行,使得所有的列有且只有1个1。输出选出的行的行数和行号。
解法:这是一种精确覆盖模型。用dancinglink,看了很多博客,看吐了终于理解了。不得不说dancinglink很神奇,不过写起来太麻烦。搞一个模版以后用就好了。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define max1 100300#define max2 1010using namespace std;int R[max1],L[max1],U[max1],D[max1];//x的右左上下。int C[max1],mark[max1];//x所在的列号,x所在的行号。int h[max2],s[max2];//左右头指针,x列1的个数。int num,n,m,ans[max2],flag;void link(int r,int c)//建图{   //连接列    s[c]++;C[num] = c;    U[num] = U[c];D[U[c]] = num;    U[c] = num;D[num] = c;    //连接行    if(h[r]==-1) h[r] = L[num] = R[num] = num;    else    {        L[num] = L[h[r]];R[L[h[r]]] = num;        L[h[r]] = num; R[num] = h[r];    }    mark[num] = r;    num++;}void remove1(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];            s[C[j]]--;        }    }}void reuse(int c){    for(int i=U[c];i!=c;i=U[i])//列    {        for(int 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 dancing(int k){    if(R[0]==0)//所有的列都被覆盖了。    {        flag = 1;        printf("%d",k);        for(int i = 0 ; i < k ; i ++)        {            printf(" %d",mark[ans[i]]);        }        printf("\n");        return ;    }    int min1=0x7fffffff;    int c = 0;    for(int i = R[0] ; i != 0 ; i = R[i])    {//选列数中1比较少的列来作为起始点。        if(min1>s[i])        {            min1 = s[i];            c = i;        }    }    remove1(c);    for(int i = D[c];i != c ; i = D[i])    {        ans[k] = i;//选行        for(int j = R[i] ; j != i ; j = R[j])            remove1(C[j]);//删除列对应的行        dancing(k+1);        if(flag) return;        for(int j = L[i] ; j !=i ; j = L[j])            reuse(C[j]);//恢复列对应的行    }    reuse(c);}int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        for(int i = 0 ; i <= m ; i ++)        {            s[i] = 0;            U[i] = D[i] = i;            R[i] = i+1;            L[i+1] = i;        }        R[m] = 0;        num = m + 1;        memset(h,-1,sizeof(h));        memset(mark,0,sizeof(mark));        for(int i = 1 ; i <= n ; i++)        {            int t;            cin>>t;            while(t--)            {                int x;                cin>>x;                link(i,x);            }        }        flag = 0;        dancing(0);        if(!flag) printf("NO\n");    }    return 0;}
0 0