Time Limit: 15000MS | Memory Limit: 131072KB | 64bit IO Format: %lld & %llu |
Description
Input
Output
Sample Input
Sample Output
3 2 4 6
Source
#include<cstdio>
#define MAXL 1100
int tot,root=0;//root处于最左上角(0,0)
int U[MAXL*MAXL],D[MAXL*MAXL],L[MAXL*MAXL],R[MAXL*MAXL];//根据节点编号来获取邻居
int Ccnt[MAXL];//根据pos得到列上节点计数器
int Rrt[MAXL],Crt[MAXL];//根据pos得到行/列上根节点的编号
int Row[MAXL*MAXL],Col[MAXL*MAXL];//根据节点编号得到节点位置
int ans[MAXL],top;
void Remove(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]){//终究要回到原位 向右删除
//if(!Col[j])continue;//???
//因为
U[D[j]]=U[j];//删除 断开上下的链
D[U[j]]=D[j];
Ccnt[Col[j]]--;//列上节点计数器-1
}
}
void Resume(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]]=D[U[j]]=j;
Ccnt[Col[j]]++;
}
L[R[c]]=R[L[c]]=c;
}
bool dfs(){
if(R[root]==root)//随便都可以,相当于把所有列都删完了
return true;
int minn=10000,at;
for(int p=R[root];p!=root;p=R[p]){
if(Ccnt[Col[D[p]]]<minn)//非虚拟节点才能获取row,col的值 所以用D[p]
minn=Ccnt[Col[D[p]]],at=p;
}
Remove(at);//删除一整列
for(int i=D[at];i!=at;i=D[i]){
//表示有行在这一列上为1(相互冲突)
ans[top++]=Row[i];//记录答案
for(int j=R[i];j!=i;j=R[j])//删除这一整行(行上为1的节点)
Remove(Col[j]);//这里给的是位置?????????
//向下深搜(删除)
if(dfs())return true;
for(int j=L[i];j!=i;j=L[j])
Resume(Col[j]);//这里给的是位置?????????
top--;
}
Resume(at);
return false;
}
char g[MAXL][MAXL];
int main(){
int row,col,begin,end;
while(~scanf("%d%d",&row,&col)){
for(int i=0;i<=col;i++)//初始化列的链表表头 编号就是列的编号
Ccnt[i]=0,L[i]=i-1,R[i]=i+1,U[i]=D[i]=i;
L[0]=col;//环状连接
R[col]=0;
root=0;//归位指针
top=1;
tot=col+1;//前面的列已经被编号 所以从col+1开始
for(int i=1;i<=row;i++){
int tmp,t2;
scanf("%d",&tmp);
begin=end=tot;
for(int j=1;j<=tmp;j++){
scanf("%d",&t2);
Ccnt[t2]++;
Col[tot]=t2;
Row[tot]=i;
U[tot]=t2;//插入列
D[tot]=D[t2];
U[D[t2]]=tot;
D[t2]=tot;
L[tot]=end;//插入列 (在队尾)
R[tot]=begin;
L[begin]=tot;
R[end]=tot;
end=tot++;
}
}
if(!dfs())puts("NO");
else {
printf("%d",top-1);
for(int i=1;i<top;i++)
printf(" %d",ans[i]);
puts("");
}
}
}