当前位置: 首页 > news >正文

苏州新区网站制作公司/站长推荐入口自动跳转

苏州新区网站制作公司,站长推荐入口自动跳转,怎么样做搜索引擎网站,网站设计建设公司精确覆盖(Exact Cover)问题 精确覆盖 S 为集合 X 的若干个子集构成的集合,若存在 S 的一个子集 S*,满足 X 中的元素有且只有一次包含在 S* 的一个元素中,那么称 S* 为 X 的一个精确覆盖。 S*属性 根据定义 S* 具有…

精确覆盖(Exact Cover)问题

精确覆盖

S 为集合 X 的若干个子集构成的集合,若存在 S 的一个子集 S*,满足 X 中的元素有且只有一次包含在 S* 的一个元素中,那么称 S* 为 X 的一个精确覆盖。

S*属性

根据定义 S* 具有以下属性:
1. S* 中任意两个元素交集为空。
2. S* 中所有元素并集为 X。

例子

假定 S = { A, B, C, D} ,X = {1, 2, 3, 4, 5, 6} ,其中:
A = {1, 3, 5}
B = {2, 4}
C = {2, 3, 4, 5, 6}
D = {2, 4, 6}
那么 S* = {A, D} 是 X 的一个精确覆盖。而 {A, B}、{A, C}
分别不满足上述属性2、1,因而不是 X 的一个精确覆盖。

精确覆盖问题

精确覆盖问题是指给定一个 S,确定是否存在对 X 的一个精确覆盖,这是一个 NP 难问题。
这个问题可以用一个矩阵来表示
矩阵表示
在矩阵表示情形下,精确覆盖问题可以表述为选择特定的行使得所有的列有且只含有一个1。
精确覆盖

Algorithm X

X
不要被名字吓到,Donald E. Knuth 这么叫它的,本质上还是一个回溯法。其步骤如下所示:
维护两个集合——当前尚未满足的限制条件和可供选择的选项。
1.检查当前未满足的限制条件集合,若为空,则表示问题已经解决,输出答案并返回
2.否则选择其中一个不满足的限制条件。(可以使用启发式算法尽量加快代码运行)
3.找满足限制条件的选项集合,若为空,则表示当前这个位置不可能产出正确答案,返回。(剪枝)
4.否则,遍历上述选项集合(这一步可以是随机选择,这样会导致一个 non-deterministic 算法):
(1)当前选项可能满足多个限制条件,故对每个满足的限制条件,将其从未满足限制条件集合中移除,并且将所有能满足这个限制条件的选项也移除(因为精确覆盖要求不可重叠,若考虑完全覆盖则此时不需要移除)
(2)上述操作完成后形成“尚未满足的限制条件”和“可供选择的选项”这两个集合的子集合——即子问题,对此子问题递归求解。
(3)复原:上述递归完成后,在测试下一个选项前,我们需要恢复原来两个集合的样子。所以要将之前移除的条件和选项全部恢复。
使用 X 算法对上述例子求解如下:
X算法求解

可以看出上述操作需要一对对偶操作——将一个元素从矩阵中移除,一番操作完成后还要将移除的这个元素重新添加回矩阵中去,这个用普通结构实现可能会比较复杂。

Insight——双向链表操作

将双向链表中的一个元素拿掉

x.left.right=x.right
x.right.left=x.left

双向链表删除
将该元素重新加入链表

x.left.right=x
x.right.left=x

双向链表恢复

DLX

我们可以类似地将每个节点都弄成四路链表,将所有连同节点连接起来,如下图所示:
4 way mesh
再加上约束条件属性和一些其他属性,我们的节点可以声明为如下形式:

struct Node
{
public:struct Node *left;struct Node *right;struct Node *up;struct Node *down;struct Node *column;int rowID;int colID;int nodeCount;
};

问题矩阵转化为DLX
只需要找到每个节点四个方向最邻近的“1”即可。这相当于将原先二维的一张平面扭曲成一个三维圆环面,如下图所示(来自3blue1brown):
平面2环面

Node *createToridolMatrix()
{for(int i = 0; i <= nRow; i++){for(int j = 0; j < nCol; j++){if(ProbMat[i][j]){int a, b;// first row represent constraintsif(i) Matrix[0][j].nodeCount += 1;Matrix[i][j].column = &Matrix[0][j];Matrix[i][j].rowID = i;Matrix[i][j].colID = j;// Left pointera = i; b = j;do{ b = getLeft(b); } while(!ProbMat[a][b] && b != j);Matrix[i][j].left = &Matrix[i][b];// Right pointera = i; b = j;do { b = getRight(b); } while(!ProbMat[a][b] && b != j);Matrix[i][j].right = &Matrix[i][b];// Up pointera = i; b = j;do { a = getUp(a); } while(!ProbMat[a][b] && a != i);Matrix[i][j].up = &Matrix[a][j];// Down pointera = i; b = j;do { a = getDown(a); } while(!ProbMat[a][b] && a != i);Matrix[i][j].down = &Matrix[a][j];}}}//configure headerheader->right = &Matrix[0][0];header->left = &Matrix[0][nCol-1];Matrix[0][0].left = header;Matrix[0][nCol-1].right = header;return header;
}

删除节点
类比双向链表的删除即可,其主要删除两部分:属性和满足该属性行除本属性外其它所有子节点。略拗口,还是看图示吧。
remove
这是因为无论具体选择哪一行,另一行的其它节点都因为本属性互斥和不能发挥作用消除限制条件),所以把他们暂时屏蔽(删除)掉。
另外要注意只删除上下链,不删除左右链!

void remove(struct Node *targetNode)
{struct Node *row, *rightNode;struct Node *colNode = targetNode->column;//delete constraintscolNode->left->right = colNode->right;colNode->right->left = colNode->left;//remove each rowfor(row = colNode->down; row != colNode; row = row->down){for(rightNode = row->right; rightNode != row;rightNode = rightNode->right){rightNode->up->down = rightNode->down;rightNode->down->up = rightNode->up;Matrix[0][rightNode->colID].nodeCount -= 1;}}
}

恢复节点
理解了删除节点,恢复节点就容易了,是上述过程的逆过程。

void resume(struct Node *targetNode)
{struct Node *rowNode, *leftNode;struct Node *colNode = targetNode->column;//resume row    for(rowNode = colNode->up; rowNode != colNode; rowNode = rowNode->up){for(leftNode = rowNode->left; leftNode != rowNode;leftNode = leftNode->left){leftNode->up->down = leftNode;leftNode->down->up = leftNode;          Matrix[0][leftNode->colID].nodeCount += 1;}    }// resume headercolNode->left->right = colNode;colNode->right->left = colNode;
}

启发式选择列
我们先选择列节点数个数最少的来挑选,因为先选择其它的这个可能就被限制无法进行选择了。

Node *getMinColumn()
{struct Node *h = header;struct Node *min_col = h->right;h = h->right->right;do{if(h->nodeCount < min_col->nodeCount){min_col = h;}h = h->right;}while(h != header);return min_col;
}

Let’s dancing!
首先选择某一列,然后对满足该列的行进行遍历,每遍历一行,删除此行中同时满足其它列,进行递归即可。注意递归完成要恢复原样。

void dancing(int k)
{struct Node *rowNode;struct Node *rightNode;struct Node *leftNode;struct Node *column;//found solutionif(header->right == header){printSolutions();return;}// heuristic choose columncolumn = getMinColumn();// remove chosen columnremove(column);for(rowNode = column->down; rowNode != column;rowNode = rowNode->down ){solutions.push_back(rowNode);for(rightNode = rowNode->right; rightNode != rowNode;rightNode = rightNode->right)remove(rightNode);// recursive solve problemsearch(k+1);// if solution in not possible, backtrack (resume)solutions.pop_back();column = rowNode->column;for(leftNode = rowNode->left; leftNode != rowNode;leftNode = leftNode->left)resume(leftNode);}resume(column);
}

应用

对于有约束条件的搜索问题,我们可以将约束条件转化为每一列,而将所有可能情形转化为行,那么问题就转化为了前文中的矩阵情形:找出所有可能的行组合使得所有列有且只有一个1!举例如下:
1.拼图问题
找出是否存在一种方案,使得使用给定积木恰好填满给定区域。
拼图
2.数独求解
数独
3.N皇后问题
N皇后问题
具体怎么映射限制条件还是有一定 trick 的,这个以后有时间再单独拎出来分析一哈吧。

总结

本文主要介绍了精确覆盖问题、Algorithm X 与 DLX,给出了 DLX 的主要操作 remove 和 resume。同时点出了其在解决完全覆盖中的可能方案。最后介绍了精确覆盖问题在实际中的一些应用。

致谢

本文图片部分来自 Wei Li & Atul Kumar & 3blue1brown。同时由衷感谢 Donald E. Knuth 老爷爷!

http://www.jmfq.cn/news/5188573.html

相关文章:

  • 潮汕美食网站怎么做/营销公司
  • dwcc2017做网站教程/app开发定制
  • 苹果cms做网站/公司网站制作需要多少钱
  • 桂林北站到龙脊梯田/百度快速排名优化技术
  • 伍佰亿网站怎样/网页设计教程
  • 最优网络做网站骗/广州抖音推广
  • wordpress 回车换行/谷歌seo代运营
  • 做旅游网站的社会效益可行性/日结app推广联盟
  • 自己做网站必须要学哪些/河南平价的seo整站优化定制
  • 福建有没有网站做一件代发/长沙关键词快速排名
  • 手机网站有免费做的吗/社群营销方案
  • 门户网站什么意思/网络推广怎么赚钱
  • 商城网站制作/人工智能培训班收费标准
  • 做网站关键词/高端网站建设深圳
  • 企业网站备案意义/湖南正规关键词优化报价
  • 做1元夺宝网站挣钱吗/网络策划方案
  • 软件网站的服务器/深圳专门做seo的公司
  • 表格如何给网站做链接地址/百度客户端在哪里打开
  • 做个网站大约多少钱/营销型网站制作公司
  • 做电影方面的网站怎么做/网络舆情管理
  • 娄底企业网站建设制作/b站视频推广
  • 淄博政府网站建设专家/百度客服系统
  • 衢州建筑结构加固哪家好/北京seo优化多少钱
  • 厦门专业网站设计代理/南和网站seo
  • 企业网站的常见类型有什么/西安做网站哪家好
  • 网站做多久才能每日上万/精准ip地址查询工具
  • 网站标签怎么设置/武汉seo全网营销
  • 沈阳电商网站建设/百度一下照片识别
  • 陇南网站网站建设/安全又舒适的避孕方法有哪些
  • 鳌江网站建设/正规考证培训机构