Dancing Links的重复覆盖问题解法
众所周知,DLX对于解决精确覆盖问题有非常出奇的效果,但我们现在考虑一种叫做重复覆盖的问题。其实这一问题是我们看到DL的论文第一部分时,对Dancing Links用法的初次想法。它就是单纯利用了链表的性质进行的模拟(请允许我这么说),但抽象而言,就是对0/1矩阵进行如下操作:选取一些行,使所有的列都有‘1’(想想与精确覆盖的不同之处)。在实现上,不需要精确覆盖的排他性操作,而在框架上的实现则是相同的。考虑一个优化,在重复覆盖问题中,对于列长是不动态计数的,能否通过初始的排序减小常数。
以下是一般的重复覆盖问题的实现,要用到Iter-A*,使用启发函数进行加速,启发函数的设计十分简单,相信大家能看懂,此处未加过优化,如果大家有想法可以自己实现。
以下是一般的重复覆盖问题的实现,要用到Iter-A*,使用启发函数进行加速,启发函数的设计十分简单,相信大家能看懂,此处未加过优化,如果大家有想法可以自己实现。
#include <iostream>
#include <cmath>
using namespace std;
const int MAXR=60;
const int MAXC=60;
const int MAXLEN=MAXR*MAXC+MAXR+MAXC;
int L[MAXLEN];
int R[MAXLEN];
int D[MAXLEN];
int U[MAXLEN];
int nRow[MAXLEN];
int nCol[MAXLEN];
int Col[MAXC]; //判定列集是否已插入
int Row[MAXR]; //判定行集是否已插入
//int RC[MAXR][MAXC]; //判定元素是否已插入
int RS[MAXR],CS[MAXC]; //行长与列长
int eid; //内存标识
int head;
int Cn;
int MAXSTEP;
//int ans[MAXC];
/*int alen;*/
//DLX算法 进行重复覆盖
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];
int i;
for (i=U[c];i!=c;i=U[i])
{
L[R[i]]=L[i];
R[L[i]]=R[i];
}
}
//恢复列(使用cid)
inline void ResumeCol(int c)
{
//c=Col[c];
int i;
for (i=D[c];i!=c;i=D[i])
{
L[R[i]]=i;
R[L[i]]=i;
}
}
//重复覆盖 iter a*
bool hash[MAXC];
int price()
{
int i,j,k;
int ret=0;
memset(hash,0,sizeof(hash));
for (i=R[head];i!=head;i=R[i])
{
if(nCol[D[i]]==-1) continue;
if(!hash[nCol[D[i]]])
{
++ret;
hash[nCol[D[i]]]=true;
for (j=D[i];j!=i;j=D[j])
{
if (nCol[j]==-1)
{
continue;
}
for (k=R[j];k!=j;k=R[k])
{
if (nCol[k]==-1)
{
continue;
}
hash[nCol[k]]=true;
}
}
}
}
return ret;
}
inline bool dfs(int k)
{
if (k+price()>MAXSTEP)
{
return false;
}
if (R[head]==head)
{
//alen=k;
return true;
}
int i,j;
int s=INT_MAX;
int c;
for (i=L[head];i!=head;i=L[i])
{
if(nCol[D[i]]==-1) {c=i;continue;}
if (CS[nCol[D[i]]]<s)
{
s=CS[nCol[D[i]]];
c=i;
}
}
for (i=D[c];i!=c;i=D[i])
{
//ans[k]=nRow[i];
RemoveCol(i);
for (j=R[i];j!=i;j=R[j])
{
if (nCol[j]==-1)
{
continue;
}
RemoveCol(j);
}
if(dfs(k+1))
{
return true;
}
for (j=L[i];j!=i;j=L[j])
{
if (nCol[j]==-1)
{
continue;
}
ResumeCol(j);
}
ResumeCol(i);
}
return false;
}
#include <cmath>
using namespace std;
const int MAXR=60;
const int MAXC=60;
const int MAXLEN=MAXR*MAXC+MAXR+MAXC;
int L[MAXLEN];
int R[MAXLEN];
int D[MAXLEN];
int U[MAXLEN];
int nRow[MAXLEN];
int nCol[MAXLEN];
int Col[MAXC]; //判定列集是否已插入
int Row[MAXR]; //判定行集是否已插入
//int RC[MAXR][MAXC]; //判定元素是否已插入
int RS[MAXR],CS[MAXC]; //行长与列长
int eid; //内存标识
int head;
int Cn;
int MAXSTEP;
//int ans[MAXC];
/*int alen;*/
//DLX算法 进行重复覆盖
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];
int i;
for (i=U[c];i!=c;i=U[i])
{
L[R[i]]=L[i];
R[L[i]]=R[i];
}
}
//恢复列(使用cid)
inline void ResumeCol(int c)
{
//c=Col[c];
int i;
for (i=D[c];i!=c;i=D[i])
{
L[R[i]]=i;
R[L[i]]=i;
}
}
//重复覆盖 iter a*
bool hash[MAXC];
int price()
{
int i,j,k;
int ret=0;
memset(hash,0,sizeof(hash));
for (i=R[head];i!=head;i=R[i])
{
if(nCol[D[i]]==-1) continue;
if(!hash[nCol[D[i]]])
{
++ret;
hash[nCol[D[i]]]=true;
for (j=D[i];j!=i;j=D[j])
{
if (nCol[j]==-1)
{
continue;
}
for (k=R[j];k!=j;k=R[k])
{
if (nCol[k]==-1)
{
continue;
}
hash[nCol[k]]=true;
}
}
}
}
return ret;
}
inline bool dfs(int k)
{
if (k+price()>MAXSTEP)
{
return false;
}
if (R[head]==head)
{
//alen=k;
return true;
}
int i,j;
int s=INT_MAX;
int c;
for (i=L[head];i!=head;i=L[i])
{
if(nCol[D[i]]==-1) {c=i;continue;}
if (CS[nCol[D[i]]]<s)
{
s=CS[nCol[D[i]]];
c=i;
}
}
for (i=D[c];i!=c;i=D[i])
{
//ans[k]=nRow[i];
RemoveCol(i);
for (j=R[i];j!=i;j=R[j])
{
if (nCol[j]==-1)
{
continue;
}
RemoveCol(j);
}
if(dfs(k+1))
{
return true;
}
for (j=L[i];j!=i;j=L[j])
{
if (nCol[j]==-1)
{
continue;
}
ResumeCol(j);
}
ResumeCol(i);
}
return false;
}