Dancing Links
近日闲来无事,通宵写写代码,啃了下Knuth大师的论文,实在惊讶于Dancing Links的优美,于是不免心血来潮,用面向对象的方法写了近400行,结果发现很多安全隐患,遂改了下用面向过程的方式,在HUST上搞了那道1017,还不错232ms,把主要模版代码发下,希望大家指正。
#include <iostream>
using namespace std;
const int MAXN=1010;
const int MAXLEN=MAXN*100+MAXN;
int L[MAXLEN];
int R[MAXLEN];
int D[MAXLEN];
int U[MAXLEN];
int nRow[MAXLEN];
int nCol[MAXLEN];
int Col[MAXN]; //判定列集是否已插入
int Row[MAXN]; //判定行集是否已插入
int RC[MAXN][MAXN]; //判定元素是否已插入
int RS[MAXN],CS[MAXN]; //行长与列长
int eid; //内存标识
int head;
int Cn;
int N,M;
int ans[MAXN];
int alen;
//DLX算法 进行精确覆盖 判定前请先判断是否各列中都有1存在
//对于行列唯一的情况 可以考虑将RC数组取消以加速
inline void init()
{
memset(Row,-1,sizeof(Row));
memset(Col,-1,sizeof(Col));
memset(RC,-1,sizeof(RC));
memset(nCol,-1,sizeof(nCol));
memset(nRow,-1,sizeof(nRow));
head=0;
L[head]=R[head]=D[head]=U[head]=head;
eid=1;
Cn=0;
}
//插入行
inline void insRow(int r)
{
U[D[head]]=eid;
U[eid]=head;
D[eid]=D[head];
D[head]=eid;
L[eid]=R[eid]=eid;
RS[r]=1;
Row[r]=eid++;
}
//插入列
inline void insColumn(int c)
{
L[R[head]]=eid;
L[eid]=head;
R[eid]=R[head];
R[head]=eid;
U[eid]=D[eid]=eid;
CS[c]=1;
Col[c]=eid++;
}
//插入元素
inline void insElement(int r,int c)
{
int rid=Row[r];
int cid=Col[c];
L[R[rid]]=eid;
L[eid]=rid;
R[eid]=R[rid];
R[rid]=eid;
U[D[cid]]=eid;
U[eid]=cid;
D[eid]=D[cid];
D[cid]=eid;
nRow[eid]=r;
nCol[eid]=c;
++CS[c];
++RS[r];
RC[r][c]=eid;
++eid;
}
//插入操作
inline void insert(int r, int c)
{
if (Col[c]==-1)
{
++Cn;
insColumn(c);
}
if(Row[r]==-1)
{
insRow(r);
}
if(RC[r][c]==-1)
{
insElement(r,c);
}
}
//删除列(使用cid)
inline void RemoveCol(int c)
{
//c=Col[c];
L[R[c]]=L[c];
R[L[c]]=R[c];
int i,j;
for (i=D[c];i!=c;i=D[i])
{
for (j=R[i];j!=i;j=R[j])
{
if(nCol[j]==-1) continue;
U[D[j]]=U[j];
D[U[j]]=D[j];
--CS[nCol[j]];
}
}
}
//恢复列(使用cid)
inline void ResumeCol(int c)
{
//c=Col[c];
int i,j;
for (i=U[c];i!=c;i=U[i])
{
for (j=L[i];j!=i;j=L[j])
{
if(nCol[j]==-1) continue;
++CS[nCol[j]];
U[D[j]]=j;
D[U[j]]=j;
}
}
L[R[c]]=c;
R[L[c]]=c;
}
//遍历
inline void debug()
{
int i,j;
for (i=D[head];i!=head;i=D[i])
{
for (j=R[i];j!=i;j=R[j])
{
printf("%d,%d ",nRow[j],nCol[j]);
}
puts("");
}
}
//精确覆盖
inline bool dfs(int k)
{
if (R[head]==head)
{
alen=k;
return true;
}
int i,j;
int s=INT_MAX;
int c;
for (i=R[head];i!=head;i=R[i])
{
if(nCol[D[i]]==-1) {c=i;continue;}
if (CS[nCol[D[i]]]<=s)
{
s=CS[nCol[D[i]]];
c=i;
}
}
RemoveCol(c);
for (i=D[c];i!=c;i=D[i])
{
ans[k]=nRow[i];
for (j=R[i];j!=i;j=R[j])
{
if (nCol[j]==-1)
{
continue;
}
RemoveCol(Col[nCol[j]]);
}
if(dfs(k+1))
{
return true;
}
for (j=L[i];j!=i;j=L[j])
{
if (nCol[j]==-1)
{
continue;
}
ResumeCol(Col[nCol[j]]);
}
}
ResumeCol(c);
return false;
}
using namespace std;
const int MAXN=1010;
const int MAXLEN=MAXN*100+MAXN;
int L[MAXLEN];
int R[MAXLEN];
int D[MAXLEN];
int U[MAXLEN];
int nRow[MAXLEN];
int nCol[MAXLEN];
int Col[MAXN]; //判定列集是否已插入
int Row[MAXN]; //判定行集是否已插入
int RC[MAXN][MAXN]; //判定元素是否已插入
int RS[MAXN],CS[MAXN]; //行长与列长
int eid; //内存标识
int head;
int Cn;
int N,M;
int ans[MAXN];
int alen;
//DLX算法 进行精确覆盖 判定前请先判断是否各列中都有1存在
//对于行列唯一的情况 可以考虑将RC数组取消以加速
inline void init()
{
memset(Row,-1,sizeof(Row));
memset(Col,-1,sizeof(Col));
memset(RC,-1,sizeof(RC));
memset(nCol,-1,sizeof(nCol));
memset(nRow,-1,sizeof(nRow));
head=0;
L[head]=R[head]=D[head]=U[head]=head;
eid=1;
Cn=0;
}
//插入行
inline void insRow(int r)
{
U[D[head]]=eid;
U[eid]=head;
D[eid]=D[head];
D[head]=eid;
L[eid]=R[eid]=eid;
RS[r]=1;
Row[r]=eid++;
}
//插入列
inline void insColumn(int c)
{
L[R[head]]=eid;
L[eid]=head;
R[eid]=R[head];
R[head]=eid;
U[eid]=D[eid]=eid;
CS[c]=1;
Col[c]=eid++;
}
//插入元素
inline void insElement(int r,int c)
{
int rid=Row[r];
int cid=Col[c];
L[R[rid]]=eid;
L[eid]=rid;
R[eid]=R[rid];
R[rid]=eid;
U[D[cid]]=eid;
U[eid]=cid;
D[eid]=D[cid];
D[cid]=eid;
nRow[eid]=r;
nCol[eid]=c;
++CS[c];
++RS[r];
RC[r][c]=eid;
++eid;
}
//插入操作
inline void insert(int r, int c)
{
if (Col[c]==-1)
{
++Cn;
insColumn(c);
}
if(Row[r]==-1)
{
insRow(r);
}
if(RC[r][c]==-1)
{
insElement(r,c);
}
}
//删除列(使用cid)
inline void RemoveCol(int c)
{
//c=Col[c];
L[R[c]]=L[c];
R[L[c]]=R[c];
int i,j;
for (i=D[c];i!=c;i=D[i])
{
for (j=R[i];j!=i;j=R[j])
{
if(nCol[j]==-1) continue;
U[D[j]]=U[j];
D[U[j]]=D[j];
--CS[nCol[j]];
}
}
}
//恢复列(使用cid)
inline void ResumeCol(int c)
{
//c=Col[c];
int i,j;
for (i=U[c];i!=c;i=U[i])
{
for (j=L[i];j!=i;j=L[j])
{
if(nCol[j]==-1) continue;
++CS[nCol[j]];
U[D[j]]=j;
D[U[j]]=j;
}
}
L[R[c]]=c;
R[L[c]]=c;
}
//遍历
inline void debug()
{
int i,j;
for (i=D[head];i!=head;i=D[i])
{
for (j=R[i];j!=i;j=R[j])
{
printf("%d,%d ",nRow[j],nCol[j]);
}
puts("");
}
}
//精确覆盖
inline bool dfs(int k)
{
if (R[head]==head)
{
alen=k;
return true;
}
int i,j;
int s=INT_MAX;
int c;
for (i=R[head];i!=head;i=R[i])
{
if(nCol[D[i]]==-1) {c=i;continue;}
if (CS[nCol[D[i]]]<=s)
{
s=CS[nCol[D[i]]];
c=i;
}
}
RemoveCol(c);
for (i=D[c];i!=c;i=D[i])
{
ans[k]=nRow[i];
for (j=R[i];j!=i;j=R[j])
{
if (nCol[j]==-1)
{
continue;
}
RemoveCol(Col[nCol[j]]);
}
if(dfs(k+1))
{
return true;
}
for (j=L[i];j!=i;j=L[j])
{
if (nCol[j]==-1)
{
continue;
}
ResumeCol(Col[nCol[j]]);
}
}
ResumeCol(c);
return false;
}