最基础的dancing links的精确覆盖题目

 

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <algorithm>
  5 
  6 using namespace std;
  7 #define N 1005
  8 #define MAXN 1000100
  9 
 10 struct DLX{
 11     int n , m , size;//size表示当前dlx表中有多少个元素
 12     int ans[N] , k;//ans[]记录选取的行
 13     int U[MAXN] , D[MAXN] , L[MAXN] , R[MAXN];
 14     int row[MAXN] , col[MAXN] ; // 分别表示第 i 号节点属于第几行或者第几列
 15     int cnt_col[N];//分别表示第i行或者第i列有多少个节点
 16     int first[N]; //行上的起始指针
 17 
 18     void init(int _n , int _m)
 19     {
 20         n = _n , m = _m;
 21         size = m;
 22         for(int i=0 ; i<=m ; i++){
 23             U[i] = D[i] = i;
 24             L[i] = i-1 , R[i] = i+1;
 25         }
 26         L[0] = m , R[m] = 0;
 27         for(int i=1 ; i<=n ; i++) first[i]=-1;
 28         for(int i=1 ; i<=m ; i++) cnt_col[i] = 0;
 29        // for(int i=0 ; i<=n ; i++)  cout<<"here: "<<i<<" "<<L[i]<<" "<<R[i]<<endl;
 30     }
 31 
 32     void link(int r , int c)
 33     {
 34         ++size;
 35         //修改列上的情况
 36         D[size] = D[c] , U[D[c]] = size;
 37         U[size] = c , D[c] = size;
 38         cnt_col[c]++ , col[size] = c ;
 39 
 40         //修改行上的情况
 41         if(first[r]<0) first[r] = L[size] = R[size] = size;
 42         else{
 43             R[size] = R[first[r]] , L[R[first[r]]] = size;
 44             L[size] = first[r] , R[first[r]] = size;
 45         }
 46       //  cout<<" r: "<<r<<" c: "<<c<<" "<<size<<" "<<L[size]<<" "<<R[size]<<" "<<U[size]<<" "<<D[size]<<endl;
 47         row[size] = r;
 48     }
 49 
 50     void Remove(int c)
 51     {
 52         L[R[c]] = L[c] , R[L[c]] = R[c];
 53         for(int i=D[c] ; i!=c ; i=D[i]){
 54             for(int j=R[i] ; j!=i ; j=R[j]){
 55                 D[U[j]] = D[j] , U[D[j]] = U[j];
 56                 --cnt_col[col[j]];
 57             }
 58         }
 59     }
 60 
 61     void Resume(int c)
 62     {
 63         for(int i=U[c] ; i!=c ; i=U[i]){
 64             for(int j=L[i] ; j!=i ; j=L[j]){
 65                 U[D[j]] = D[U[j]] = j;
 66                 ++cnt_col[col[j]];
 67             }
 68         }
 69         R[L[c]] = L[R[c]] = c;
 70     }
 71 
 72     bool Dance(int d)
 73     {
 74 
 75         if(!R[0]){
 76             k = d;
 77             return true;
 78         }
 79         int st = R[0];
 80         //找到能删除最少节点的列先删除,这样递归的行的次数就会减少,提高效率
 81         for(int i=st ; i!=0 ; i=R[i]){
 82             if(cnt_col[st]>cnt_col[i])
 83                 st = i;
 84         }
 85 
 86         Remove(st);
 87         for(int i=D[st] ; i!=st ; i=D[i]){
 88             ans[d] = row[i];
 89             for(int j=R[i] ; j!=i ; j=R[j]) Remove(col[j]);
 90             if(Dance(d+1)) return true;
 91             for(int j=L[i] ; j!=i ; j=L[j]) Resume(col[j]);
 92         }
 93         Resume(st);
 94         return false;
 95     }
 96 }dlx;
 97 
 98 int main()
 99 {
100    // freopen("a.in" , "r" , stdin);
101     int n , m;
102 
103     while(~scanf("%d%d" , &n , &m))
104     {
105         dlx.init(n , m);
106         for(int r=1 ; r<=n ; r++){
107             int m , c;
108             scanf("%d" , &m);
109             for(int i=0 ; i<m ; i++){
110                 scanf("%d" , &c);
111                 dlx.link(r , c);
112             }
113         }
114         bool ok = dlx.Dance(0);
115         if(ok){
116             printf("%d" , dlx.k);
117             sort(dlx.ans , dlx.ans+dlx.k);
118             for(int i=0 ; i<dlx.k ; i++) printf(" %d" , dlx.ans[i]);
119             puts("");
120         }
121         else puts("NO");
122     }
123     return 0;
124 }

 

 posted on 2015-05-15 00:38  Love风吟  阅读(197)  评论(0编辑  收藏  举报