#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