标签:poj dlx dance links 搜索
题意:
给出一个n*m的01矩阵,选择其中的一些行,来精确覆盖每一列;
只需要输出是否存在解即可;
n<=16,m<=300;
题解:
DLX裸题,利用双向十字链表优化搜索中的回溯问题;
因为每一列上都只能有且仅有一个1,所以如果某一列上已经有了1,那么这一列上有1的其他行也可以被删除;
根据这个思想是我们有了一个很厉害的剪枝条件,但是如果直接在矩阵中删除速度太慢,要求空间太多;
所以就有了这种支持快速删除与恢复的数据结构——双向链表的优化;
具体实现上,我觉得还是指针比较靠谱,因为所以指针都是循环的所以不存在访问NULL的问题;
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 20 #define M 310 using namespace std; struct node { node *l,*r,*u,*d; int belong; }buf[N*M],*head,*c[M]; int tot,cnt[M]; bool map[N][M]; node *newnode() { return &buf[++tot]; } void Build(int n,int m) { tot=0; head=newnode(); for(int i=1;i<=m;i++) c[i]=newnode(); for(int i=1;i<=m;i++) { c[i]->l=c[i-1],c[i]->r=c[i+1]; c[i]->u=c[i],c[i]->d=c[i]; } c[1]->l=head,c[m]->r=head; head->r=c[1],head->l=c[m]; for(int i=1;i<=n;i++) { node *t=NULL; for(int j=1;j<=m;j++) { if(map[i][j]) { node *now=newnode(); if(t==NULL) now->l=now->r=now; else now->l=t,now->r=t->r, t->r=now,now->r->l=now; now->belong=j; now->u=c[j]->u; now->d=c[j]; c[j]->u->d=now; c[j]->u=now; t=now; } } } } void remove(node *x) { x->l->r=x->r; x->r->l=x->l; for(node *t=x->d;t!=x;t=t->d) { for(node *k=t->r;k!=t;k=k->r) { k->u->d=k->d; k->d->u=k->u; } } } void resume(node *x) { x->l->r=x; x->r->l=x; for(node *t=x->d;t!=x;t=t->d) { for(node *k=t->r;k!=t;k=k->r) { k->u->d=k; k->d->u=k; } } } bool dfs() { node *t=head->r; if(t==head) return 1; for(node *i=t->d;i!=t;i=i->d) { remove(t); for(node *j=i->r;j!=i;j=j->r) { remove(c[j->belong]); } if(dfs()) return 1; for(node *j=i->r;j!=i;j=j->r) { resume(c[j->belong]); } resume(t); } return 0; } int main() { int n,m,i,j,k; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { scanf("%d",&map[i][j]); } } Build(n,m); if(dfs()) puts("Yes, I found it"); else puts("It is impossible"); } return 0; }
标签:poj dlx dance links 搜索
原文地址:http://blog.csdn.net/ww140142/article/details/49777273