【HUST - 1017】精確覆蓋問題 Exact Cover DLX 解題報告

Time Limit: 15000MS   Memory Limit: 131072KB   64bit IO Format: %lld & %llu

Description

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.

Input

There 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.

Output

First 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 3 5 6
3 4 5 7
2 2 7
4 2 3 6 7

Sample Output

3 2 4 6

Source

dupeng





DLX。。
直接貼代碼,有註釋(原諒我生性懶惰)
#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("");
		}
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章