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("");
}
}
}