DLX精准覆盖模板
使用版
const int maxn = 200;
const int maxr = 200;
const int maxnode = 1e6;
struct DLX{
int U[maxnode], D[maxnode], L[maxnode], R[maxnode];
int row[maxnode], col[maxnode];
int S[maxn], H[maxr], ans[maxr], ansd, sz;
int n,m;
void init(int n, int m){
this->n = n; this->m = m;
for(int i = 0; i <= m; i++){
L[i] = i-1; R[i] = i+1; U[i] = D[i] = i;
}
L[0] = m; R[m] = 0; sz = m+1;
memset(S, 0, sizeof(S));
memset(H, -1, sizeof(H));
}
void addNode(int r, int c){
row[sz] = r; col[sz] = c;
U[sz] = U[c]; D[sz] = c;
D[U[sz]] = sz; U[D[sz]] = sz;
if(H[r] == -1){
L[sz] = sz; R[sz] = sz;
H[r] = sz;
}else{
R[sz] = H[r]; L[sz] = L[H[r]];
L[R[sz]] = sz; R[L[sz]] = sz;
}
S[col[sz]]++; sz++;
}
#define FOR(i, A, s) for(int i = A[s]; i != s; i = A[i])
void remove(int c){
R[L[c]] = R[c]; L[R[c]] = L[c];
FOR(i, D, c) FOR(j, R, i){
U[D[j]] = U[j]; D[U[j]] = D[j]; S[col[j]]--;
}
}
void restore(int c){
FOR(i, U, c) FOR(j, L, i){
U[D[j]] = j; D[U[j]] = j; S[col[j]]++;
}
R[L[c]] = c; L[R[c]] = c;
}
bool dfs(int d){
if(R[0] == 0){
ansd = d;
return true;
}
int c = R[0];
FOR(i, R, 0){
if(S[i] < S[c]) c = i;
}
remove(c);
FOR(i, D, c){
ans[d] = row[i];
FOR(j, R, i) remove(col[j]);
if(dfs(d+1)) return true;
FOR(j, L, i) restore(col[j]);
}
restore(c);
return false;
}
}dlx;
释疑版
const int maxn=18000;
//ans用来记录答案的编号
int ans[maxn];
struct DLX{
//左右上下,四个数组
int left[maxn],right[maxn],up[maxn],down[maxn];
//列数组,头数组,loc代表这个数在数独中的位置和数值
int col[maxn],head[maxn],loc[maxn][3];
//num数组保存每列有几个数,id为编号
int num[1030],id;
//创建有m列的矩阵
void init(int n){
for(int i=0;i<=n;i++){
up[i]=down[i]=i;
left[i]=i-1;
right[i]=i+1;
}
left[0]=n; right[n]=0;
id=n;
memset(num,0,sizeof(num));
memset(head,-1,sizeof(head));
}
//插入位于x,y的数,并对其上下左右,列和编号初始化,对px,py,pz存入loc数组
void Link(int x,int y,int px,int py,int k){
++id;
down[id]=y;
up[id]=up[y];
down[up[y]]=id;
up[y]=id;
loc[id][0]=px,loc[id][1]=py,loc[id][2]=k;//存放数的位置和数
col[id]=y;
num[y]++;//此列1的数量加一
if(head[x]==-1){
head[x]=left[id]=right[id]=id;
}
else{
int a=head[x];
int b=right[a];
left[id]=a; right[a]=id;
right[id]=b; left[b]=id;
head[x]=id;
}
}
//移除c列和c列上数所在的每一行,
void Remove(int c){
left[right[c]]=left[c];
right[left[c]]=right[c];
for(int i=down[c];i!=c;i=down[i])
for(int j=right[i];j!=i;j=right[j]){
up[down[j]]=up[j];
down[up[j]]=down[j];
num[col[j]]--;
}
}
//恢复c列和c列上数所在的每一行,
void Resume(int c){
for(int i=up[c];i!=c;i=up[i])
for(int j=right[i];j!=i;j=right[j]){
num[col[j]]++;
up[down[j]]=j;
down[up[j]]=j;
}
left[right[c]]=c;
right[left[c]]=c;
}
bool dfs(int step){
//如果走到第256步时已走完所有的数独中的数,所以退出
if(step==256) return true;
//如果头指向第0列,说明所有列已删除
if(right[0]==0) return false;
int c=right[0];
//用循环是c优先指向列中数少的列
for(int i=right[0];i;i=right[i]){
if(num[i]<num[c]){
c=i;
}
}
//删除第c列
Remove(c);
for(int i=down[c];i!=c;i=down[i]){
//记录每此循环选的编号
ans[step]=i;
//遍历i所在的行,并删除j所在的列
for(int j=right[i];j!=i;j=right[j]) Remove(col[j]);
//如果循环下去有解,则返回true
if(dfs(step+1)) return true;
//遍历i所在的行,并恢复j所在的列
for(int j=left[i];j!=i;j=left[j]) Resume(col[j]);
}
//恢复第c列
Resume(c);
//所有操作完成后仍无解,则返回false
return false;
}
}dlx;