POJ 3740 Easy Finding 详细讲解
2011-08-25 13:48
260 查看
[b]POJ 3740 Easy Finding
[/b]
[b]转载自http://hi.baidu.com/wangyu_cn/blog/item/69ad9e325a74b9a35edf0ecf.html
[/b]
[/b]
[b]转载自http://hi.baidu.com/wangyu_cn/blog/item/69ad9e325a74b9a35edf0ecf.html
[/b]
精确覆盖问题 给定一个由0,1组成的矩阵,找到一个行的集合,使得这些行的每一列都有且只有一个1 可以用DLX解决,DLX 里的X就是X算法: http://en.wikipedia.org/wiki/Knuth's_Algorithm_X int remove(int a) { 删除列a; 删除列a上为1的每一行; } int resume(int a) { remove的反操作; } int dfs()//X算法递归程序 { if(矩阵为空) return 1; 找到1最少的列a; remove(a) for i=a列上的为1的每一行 { remove(i行上为1的每一列); if(dfs()==1) return 1; resume(i行上为1的每一列); } resume(a); return 0; } DL 是dancing links,是种用十字链表提高X算法效率的技巧,具体内容可去搜论文,或者直接看程序 或者看这个~ http://en.wikipedia.org/wiki/Dancing_Links 矩阵的十字链表 表示: 0 1 1 0 1 0 1 1 0 1 0 0 表示为 ![]() 程序如下: #include <vector> #include <stdio.h> #include <string.h> using namespace std; const int R=16,C=301; int mat[R][C]; struct node { node *up,*down,*left,*right; int i,j; //记录每个节点的行和列 }clo[C],row[R],head,all[R*C]; //图中 蓝色的节点,黄色的节点,红色的节点,紫色的节点 int num[C];//记录每列1的个数 void remove(int c)//删除一列和关联的行 { if(c==-1) return ;//-1的列是row所在的列,不删除 clo[c].right->left=clo[c].left; clo[c].left->right=clo[c].right; for(node *ip=clo[c].down;ip!=&clo[c];ip=ip->down) { for(node *jp=ip->right;jp!=ip;jp=jp->right) { if(jp->j==-1) continue;//跳过-1的列 num[jp->j]--; jp->up->down=jp->down; jp->down->up=jp->up; } } } void resume(int c)//恢复 { if(c==-1) return; clo[c].right->left=&clo[c]; clo[c].left->right=&clo[c]; for(node *ip=clo[c].down;ip!=&clo[c];ip=ip->down) { for(node *jp=ip->right;jp!=ip;jp=jp->right) { if(jp->j==-1) continue; num[jp->j]++; jp->up->down=jp; jp->down->up=jp; } } } int dfs() { if(head.right==&head) return 1; node *minp; int min=1000000000; for(node *ip=head.right;ip!=&head;ip=ip->right) { if(num[ip->j]<min) { min=num[ip->j]; minp=ip; } }//找到1最少的列 if(min==0) return 0;//如果有全为0的列,返回失败 remove(minp->j); for(node *ip=minp->down;ip!=minp;ip=ip->down) { for(node *jp=ip->right;jp!=ip;jp=jp->right) remove(jp->j); if(dfs()==1) return 1; for(node *jp=ip->left;jp!=ip;jp=jp->left)//恢复的顺序因该和删除的顺序相反 resume(jp->j); } resume(minp->j); return 0; } void make(int m,int n)//生成十字链表 { int i,j,k; int newn=-1; memset(num,0,sizeof(num)); head.left=&head; head.right=&head; head.up=&head; head.down=&head; head.i=-1; head.j=-1;//初始化红色的节点 for(i=0;i<n;i++) { clo[i].i=-1; clo[i].j=i; clo[i].up=&clo[i]; clo[i].down=&clo[i]; clo[i].left=&head; clo[i].right=head.right; clo[i].left->right=&clo[i]; clo[i].right->left=&clo[i]; }//加入蓝色的节点 for(i=0;i<m;i++) { row[i].i=i; row[i].j=-1; row[i].left=&row[i]; row[i].right=&row[i]; row[i].up=&head; row[i].down=head.down; row[i].up->down=&row[i]; row[i].down->up=&row[i]; } //加入黄色的节点 for(i=0;i<m;i++) { for(j=0;j<n;j++) { if(mat[i][j]==0) continue; newn++; num[j]++; all[newn].i=i; all[newn].j=j; all[newn].down=&clo[j]; all[newn].up=clo[j].up; all[newn].up->down=&all[newn]; all[newn].down->up=&all[newn]; all[newn].right=&row[i]; all[newn].left=row[i].left; all[newn].right->left=&all[newn]; all[newn].left->right=&all[newn]; } }//加入紫色的节点 } int main() { int m,n;int i,j,k; for(;;) { if(scanf("%d%d",&m,&n)!=2) break; for(i=0;i<m;i++) for(j=0;j<n;j++) { scanf("%d",&mat[i][j]); } make(m,n);//由mat生成十字链表 if(dfs()) { printf("Yes, I found it\n"); } else { printf("It is impossible\n"); } } return 0; } |
相关文章推荐
- POJ 3740 Easy Finding
- [ACM] POJ 3740 Easy Finding (DLX模板题)
- poj 3740 -- Easy Finding (dfs)
- poj 3740 Easy Finding
- poj 3740 Easy Finding
- poj 3740 Easy Finding
- POJ 3740 Easy Finding(DLX精确覆盖裸题)
- poj 3740 Easy Finding(Dancing Links 精确覆盖)
- POJ 3740 Easy Finding (Exact cover problem)
- poj 3636 Dilworth定理(嵌套方形娃娃) Dilworth定理详细讲解
- poj 3740 Easy Finding 精确覆盖
- POJ3740 Easy Finding(Dancing Links)
- [ACM] POJ 3740 Easy Finding (DFS)
- POJ 3740 Easy Finding
- POJ 3740 Easy Finding
- poj 3740 Easy Finding 精确匹配
- POJ-3740-Easy Finding【DLX精确覆盖】
- 【POJ】3740 Easy Finding 精确覆盖入门题
- poj 3740 Easy Finding
- poj 1806 Frequent values(RMQ 统计次数) 详细讲解