这是我参与更文挑战的第16天,活动详情查看: 更文挑战
内容概要
从今天开始我们来学习OptaPlanner官网提供的各个案例,来强化我们所学的知识内容。其实还有很多的内容需要学习,但是到这一阶段,更需要的是强化实操能力,掌握使用方法后,我们再转过头来学习OptaPlanner的核心概念。
N Queues
在一个n大小的棋盘上放置n个皇后,使得没有两个皇后可以互相攻击。最常见的九宫格谜题是八皇后问题,n=8。
约束条件
-
使用一个有n列和n行的棋盘。
-
在棋盘上放置n个皇后。
-
没有两个皇后可以互相攻击。一个皇后可以攻击同一水平线、垂直线或对角线上的任何其它皇后。
此案例大量使用四皇后的问题作为主要例子。
一个错误的解决方案:
上面的解决方案是错误的,因为皇后A1和B0可以互相攻击(皇后B0和D0也可以)。
一个正确的解决方案:
所有的约束条件都得到了满足,所以解决方案是正确的。
请注意,大多数n皇后问题都有多个正确答案。我们将专注于为给定的n寻找单一的正确答案,而不是为给定的n寻找可能的正确答案的数量。
搜索空间大小
4queens has 4 queens with a search space of 256.
8queens has 8 queens with a search space of 10^7.
16queens has 16 queens with a search space of 10^19.
32queens has 32 queens with a search space of 10^48.
64queens has 64 queens with a search space of 10^115.
256queens has 256 queens with a search space of 10^616.
OptaPlanner已被证明可以轻松地处理5000个皇后或更多。
模型图
我们看下如何建立对象模型:
Column
列对象的属性只有一个index,就是其列的位置
public class Column {
private int index;
// ... getters and setters
}
Row
行对象的属性也只有一个index,就是其行的位置
public class Row {
private int index;
// ... getters and setters
}
Queue
皇后对象,包含了行、列属性,其中Row行是一个PlanningVariable规划变量,Column则是在组装问题数据时,初始化进去的,代表第几列的皇后,rowIndex默认是0。
public class Queen {
private Column column;
@PlanningVariable
private Row row;
public int getColumnIndex() {
return column.getIndex();
}
public int getRowIndex() {
if (row == null) {
return Integer.MIN_VALUE;
}
return row.getIndex();
}
public int getAscendingDiagonalIndex() {...}
public int getDescendingDiagonalIndex() {...}
// ... getters and setters
}
约束规则详解
规则内容
从业务逻辑当中可以抽出三个规则,业务规则是:“一个皇后可以攻击同一水平线、垂直线或对角线上的任何其它皇后”。
- 垂直线:每个
Queue的的column列属性,是在问题初始化进入的,n个皇后对应的column为0~(n-1),所以这个规则天然的不会违背,无需为其编写约束规则。 - **水平线:**这个规则很好理解,即每个
Queue的rowIndex不相等即可。 - 对角线:棋盘的对角线,分左上对角线和右下对角线,左上对角线的
columnIndex-rowIndex都相等,右上对角线columnIndex+rowIndex都相等,如此只需要判断是否存在这两者相等的1Queue即可。
规则代码
如下便是DRL的约束规则实现,N皇后的问题只有硬约束。
// ############################################################################
// Hard constraints
// ############################################################################
rule "Horizontal conflict"
when
Queen($id : id, row != null, $i : rowIndex)
Queen(id > $id, rowIndex == $i)
then
scoreHolder.addConstraintMatch(kcontext, -1);
end
// Vertical conflict is impossible due the model
rule "Ascending diagonal conflict"
when
Queen($id : id, row != null, $i : ascendingDiagonalIndex)
Queen(id > $id, ascendingDiagonalIndex == $i)
then
scoreHolder.addConstraintMatch(kcontext, -1);
end
rule "Descending diagonal conflict"
when
Queen($id : id, row != null, $i : descendingDiagonalIndex)
Queen(id > $id, descendingDiagonalIndex == $i)
then
scoreHolder.addConstraintMatch(kcontext, -1);
end
总结
这一篇章中的Drools非常的简单的,就是匹配条件,大家可以看一下上一篇章分享的Drools视频讲解,只需几分钟你就可以完全看明白这个约束规则的含义。
作业
请大家参考之前的代码,完成一个Queues的求解程序,给大家留一个问题:
❓ 为什么每条规则都加了一个 id > $id,其作用是什么呢?如果我不加这个条件的话,会带来什么影响呢?
结束语
下一篇章我们来学习一其它的例子。
创作不易,禁止未授权的转载。如果我的文章对您有帮助,就请点赞/收藏/关注鼓励支持一下吧💕💕💕💕💕💕