Exact cover HUST - 1017

There is an N*M matrix with only 0s and 1s, (1 <= N,M <= 1000). An exact cover is a selection of rows such that every column has a 1 in exactly one of the selected rows. 
Try to find out the selected rows. 
InputThere are multiply test cases. 
First line: two integers N, M; 
The following N lines: Every line first comes an integer C(1 <= C <= 100), represents the number of 1s in this row, then comes C integers: the index of the columns whose value is 1 in this row. 
OutputFirst output the number of rows in the selection, then output the index of the selected rows. 
If there are multiply selections, you should just output any of them. 
If there are no selection, just output "NO". 
Sample Input

6 7
3 1 4 7
2 1 4
3 4 5 7
3 3 5 6
4 2 3 6 7
2 2 7

Sample Output

3 2 4 6

题意,从一个n*m的矩阵选若干行,使得每列在所选行中恰好有一个1。输入 第一行:两个整数N,M; 
以下N行:每行首先出现一个整数C(1 <= C <= 100),表示该行中1的个数,然后是C个整数:该行中值为1的列的索引。 
输出:首先输出选择中的行数,然后输出所选行的索引。 
如果有多个选择,您应该只输出它们中的任何一个。 
如果没有选择,只输出“NO”。 

思路:精确覆盖问题用Dancing Links X 算法求解,详细情况见代码

代码:
  1 #include <cstdio>
  2 #include <fstream>
  3 #include <algorithm>
  4 #include <cmath>
  5 #include <deque>
  6 #include <vector>
  7 #include <queue>
  8 #include <string>
  9 #include <cstring>
 10 #include <map>
 11 #include <stack>
 12 #include <set>
 13 #include <sstream>
 14 #include <iostream>
 15 #define mod 1000000007
 16 #define eps 1e-6
 17 #define ll long long
 18 #define INF 0x3f3f3f3f
 19 using namespace std;
 20 
 21 struct{
 22     int n,m;//n表示行数,m表是列数
 23     int left[1001010],right[1001010],up[1001010],down[1001010],col[1001010],row[1001010];
 24     //  左,右,上,下,列,行
 25     int head[1010],ans[1010];
 26     //   头,答案
 27     int ansed,size;
 28     //   计数,标识
 29     void init(int _n,int _m)//初始化数据
 30     {
 31         n=_n;
 32         m=_m;
 33         //建立矩阵的第0行
 34         for(int i=0;i<=m;i++)
 35         {
 36             up[i]=i;
 37             down[i]=i;
 38             left[i]=i-1;
 39             right[i]=i+1;
 40             col[i]=i;
 41             row[i]=0;
 42         }
 43         left[0]=m;
 44         right[m]=0;
 45         size=m;
 46         memset(head,-1,sizeof(head));
 47         memset(ans,0,sizeof(ans));
 48         ansed=0;
 49         return ;
 50     }
 51     //插入数据
 52     void insert(int r,int c)
 53     {
 54         size++;//矩阵中存入的数是size
 55         down[size]=down[c];
 56         up[size]=c;
 57         up[down[c]]=size;
 58         down[c]=size;
 59         row[size]=r;
 60         col[size]=c;
 61         if(head[r]<0)//每一行存入第一个数时
 62         {
 63             head[r]=size;
 64             left[size]=right[size]=size;
 65         }
 66         else
 67         {
 68             left[size]=head[r];
 69             right[size]=right[head[r]];
 70             left[right[head[r]]]=size;
 71             right[head[r]]=size;
 72         }
 73         return ;
 74     }
 75     //删除数据的一列和每列对应的行
 76     void delet(int c)
 77     {
 78         //删除一列
 79         right[left[c]]=right[c];
 80         left[right[c]]=left[c];
 81         //删除行
 82         for(int i=down[c];i!=c;i=down[i])//往下循环此列的每一个数
 83         {
 84             for(int j=right[i];j!=i;j=right[j])//i所在行往右循环每一个数
 85             {
 86                 down[up[j]]=down[j];
 87                 up[down[j]]=up[j];
 88             }
 89         }
 90         return ;
 91     }
 92     //恢复数据的一列和每列对应的行
 93     void reback(int c)
 94     {
 95         //恢复行
 96         for(int i=up[c];i!=c;i=up[i])//往上循环此列的每一个数
 97         {
 98             for(int j=left[c];j!=i;j=left[j])//i所在行往左循环每一个数
 99             {
100                 down[up[j]]=i;
101                 up[down[j]]=i;
102             }
103         }
104         //恢复一列
105         right[left[c]]=c;
106         left[right[c]]=c;
107         return ;
108     }
109     //主循环
110     bool dancing(int dep)
111     {
112         if(right[0]==0)//如果Head.Right=Head,退出
113         {
114             ansed=dep;
115             return true;
116         }
117         int c=right[0];
118         delet(c);//删除上述步骤2的紫色方块
119         for(int i=down[c];i!=c;i=down[i])
120         {
121             ans[dep]=row[i];
122             //删除上述步骤3中的橙色方块
123             for(int j=right[i];j!=i;j=right[j])
124             {
125                 delet(col[j]);
126             }
127             //模拟删除后的矩阵
128             if(dancing(dep+1))
129             {
130                 return true;
131             }
132             //恢复被删除的数据
133             for(int j=left[i];j!=i;j=left[i])
134             {
135                 reback(col[j]);
136             }
137         }
138         return false;
139     }
140 }dlx;
141 int main()
142 {
143     int n,m,p,k;
144     while(scanf("%d %d",&n,&m)!=EOF)
145     {
146         dlx.init(n,m);
147         for(int i=1;i<=n;i++)
148         {
149             scanf("%d",&p);
150             for(int j=1;j<=p;j++)
151             {
152                 scanf("%d",&k);
153                 //插入第i行第k列的数
154                 dlx.insert(i,k);
155             }
156         }
157         //判断是否有结果
158         if(!dlx.dancing(0))
159         {
160             printf("NO\n");
161         }
162         else
163         {
164             printf("%d",dlx.ansed);
165             for(int i=0;i<dlx.ansed;i++)
166             {
167                 printf(" %d",dlx.ans[i]);
168             }
169             printf("\n");
170         }
171     }
172     return 0;
173 }

 

上一篇:6402. 【NOIP2019模拟11.01】Cover(启发式合并)


下一篇:codeforces1175E Minimal Segment Cover 倍增