## DLX 舞蹈链 精确覆盖 与 重复覆盖

struct DLX
{
int n , sz;                                                 // 行数，节点总数
int S[maxn];                                                // 各列节点总数
int row[maxnode],col[maxnode];                              // 各节点行列编号
int L[maxnode],R[maxnode],U[maxnode],D[maxnode];            // 十字链表

int ansd,ans[maxn];                                         // 解

void init(int n )
{
this->n = n ;
for(int i = 0 ; i <= n; i++ )
{
U[i] = i ;
D[i] = i ;
L[i] = i - 1;
R[i] = i + 1;
}
R[n] = 0 ;
L[0] = n;
sz = n + 1 ;
memset(S,0,sizeof(S));
}
{
int first = sz;
for(int i = 0 ; i < c1.size(); i++ ){
int c = c1[i];
L[sz] = sz - 1 ; R[sz] = sz + 1 ; D[sz] = c ; U[sz] = U[c];
D[U[c]] = sz; U[c] = sz;
row[sz] = r; col[sz] = c;
S[c] ++ ; sz ++ ;
}
R[sz - 1] = first ; L[first] = sz - 1;
}
// 顺着链表A，遍历除s外的其他元素
#define FOR(i,A,s) for(int i = A[s]; i != s ; i = A[i])

void remove(int c){
L[R[c]] = L[c];
R[L[c]] = R[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) {++S[col[j]];U[D[j]] = j;D[U[j]] = j; }
L[R[c]] = c;
R[L[c]] = c;
}
bool dfs(int d){
if(R[0] == 0 ){
ansd = d;
return true;
}
// 找S最小的列c
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;
}
bool solve(vector<int> & v){
v.clear();
if(!dfs(0)) return false;
for(int i = 0 ; i< ansd ;i ++ ) v.push_back(ans[i]);
return true;
}
};

DLX solver;

int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
solver.init(m);
int c , x;
vector<int> c1;
for(int i = 1; i<= n ; i ++ )
{
scanf("%d",&c);
c1.clear();
for(int j = 0 ; j < c ; j ++ ){scanf("%d",&x);c1.push_back(x);}
}
vector<int> ans;
bool flag ;
flag = solver.solve(ans);
if(flag )
{
int size1 = ans.size();
printf("%d",size1);
for(int i = 0 ; i < size1;i ++ )
printf(" %d",ans[i]);
printf("\n");
}
else printf("NO\n");
}
return 0;
}
DLX 精确覆盖 template

//明天再写。。。

const int maxn=360000;
const int maxc=500;
const int maxr=500;
const int inf=0x3f3f3f3f;
int L[maxn], R[maxn], D[maxn], U[maxn], C[maxn];
int S[maxc], H[maxr], size;
///不需要S域
{
S[c]++; C[size]=c;
U[size]=U[c]; D[U[c]]=size;
D[size]=c; U[c]=size;
if(H[r]==-1) H[r]=L[size]=R[size]=size;
else {
L[size]=L[H[r]]; R[L[H[r]]]=size;
R[size]=H[r]; L[H[r]]=size;
}
size++;
}
void remove(int c){
for (int i=D[c]; i!=c; i=D[i])
L[R[i]]=L[i], R[L[i]]=R[i];
}
void resume(int c){
for (int i=U[c]; i!=c; i=U[i])
L[R[i]]=R[L[i]]=i;
}
int h(){///用精确覆盖去估算剪枝
int ret=0;
bool vis[maxc];
memset (vis, false, sizeof(vis));
for (int i=R[0]; i; i=R[i])
{
if(vis[i])continue;
ret++;
vis[i]=true;
for (int j=D[i]; j!=i; j=D[j])
for (int k=R[j]; k!=j; k=R[k])
vis[C[k]]=true;
}
return ret;
}

int ans;
void Dance(int k){                //根据具体问题选择限制搜索深度或直接求解。
if(k+h()>=ans) return;
if(!R[0]){
if(k<ans)ans=k;
return;
}
int c=R[0];
for (int i=R[0]; i; i=R[i])
if(S[i]<S[c])c=i;
for (int i=D[c]; i!=c; i=D[i]){
remove(i);
for (int j=R[i]; j!=i; j=R[j])
remove(j);
Dance(k+1);
for (int j=L[i]; j!=i; j=L[j])
resume(j);
resume(i);
}
return ;
}

void initL(int x){///col is 1~x,row start from 1
for (int i=0; i<=x; ++i){
S[i]=0;
D[i]=U[i]=i;
L[i+1]=i; R[i]=i+1;
}///对列表头初始化
R[x]=0;
size=x+1;///真正的元素从m+1开始
memset (H, -1, sizeof(H));
///mark每个位置的名字
}

DLX 重复覆盖 template

hust1017 直接给出了精确覆盖问题的定义和模型。不用建模了，直接把输入建成矩阵即可。

zoj3209 矩阵覆盖，行数就是矩阵数，列数为要覆盖的大矩阵的格子数目（化为格子，输入的小矩阵也化为格子后一列就可以出来了）

FZU 1686 这个题，用改出来的模版死活不过，一直超时，我觉着没啥问题了还是不过。直接去找了另外的模版。另外的题都用了

hdu2295 给定n个城市，m个地点可以建造雷达，最多建k个雷达，问雷达的最小覆盖半径为多少。二分枚举覆盖半径，用重复覆盖判定可否选k个以内的雷达覆盖完所有的城市。行数即为雷达个数，列为城市个数，1为每个雷达可以覆盖到的城市的。这个题目我用的上面的重复覆盖的模版，先把答案求出来然后在判定结果，结果一直超时+wa，之后改为直接在dance的时候限制搜索深度为k就AC了。错了好多次，中间hdu坏了2次，好无奈。。。。

posted on 2013-08-12 00:35 oshixiaoxiliu 阅读(...) 评论(...) 编辑 收藏

• 随笔 - 37
• 文章 - 0
• 评论 - 10
• 引用 - 0