微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

带约束规划的方形拼图问题解决方案

如何解决带约束规划的方形拼图问题解决方案

问题: 用不接触或不重叠的正方形(任何大小)填充网格,即使在角落处也不例外。下面和右边的数字表示在相应的列/行中填充的网格方块的数量

为了解决这个问题,我应用了以下约束:放置的正方形应该是不相交的,为了确保网格正方形的数量是正确的,我将与给定行/列相交的正方形的长度总和限制为等于该行/列号。

然而,输出解决方案是 [1,1] ([NumSquares,X,Y,SquareSize],一个在坐标 (0,0) 中长度为 1 的正方形,它应该是如右图所示(13 个不同大小和坐标的方块)。

:- use_module(library(clpfd)).

:- include('utils.pl').

solve(Rows,Columns,Vars) :-
    % Domain and variables deFinition

    length(Rows,Size),MaxnumSquares is Size * Size,NumSquares #>= 0,NumSquares #< MaxnumSquares,length(StartsX,NumSquares),length(StartsY,length(SquareSizes,S is Size - 1,domain(StartsX,S),domain(StartsY,domain(SquareSizes,1,construct_squares(Size,StartsX,StartsY,SquareSizes,Squares),% Constraints

    disjoint2(Squares,[margin(0,1)]),lines_constraints(0,Rows,SquareSizes),% Solution search

    VarsList = [NumSquares,SquareSizes],flatten(VarsList,Vars),labeling([],Vars).

construct_squares(_,[],[]). 

construct_squares(Size,[StartX|T1],[StartY|T2],[SquareSize|T3],[square(StartX,SquareSize,StartY,SquareSize)|T4]) :-
    StartX + SquareSize #=< Size,StartY + SquareSize #=< Size,T1,T2,T3,T4).  

% Rows and columns NumFilledCells cells constraints

lines_constraints(_,_,_).

lines_constraints(Index,[NumFilledCells|T],Starts,SquareSizes) :-
    line_constraints(Index,NumFilledCells,I is Index + 1,lines_constraints(I,T,SquareSizes).

line_constraints(Index,SquareSizes) :-
    findall(
        SquareSize,(
            element(N,Start),element(N,SquareSize),intersect(Index,Start,SquareSize)
        ),Lines),sum(Lines,#=,NumFilledCells).
    
% Check if a square intersects a row or column

intersect(Index,SquareSize) :-
    Start #=< Index,Index #=< Start + SquareSize.

Unsolved

Solved

解决方法

问题出在您的 line_constraint/4 谓词中。在其中,您在 findall/3 中发布了一些 clpfd 约束。这意味着这些约束仅在 findall/3 内有效。这是一种重写谓词的方法,以保持张贴约束(假设您使用的是 SICStus,我使用 do 循环样式,这只是递归谓词周围的语法糖):

line_constraints(Index,NumFilledCells,Starts,SquareSizes) :-
    (
      foreach(Start,Starts),foreach(SquareSize,SquareSizes),foreach(Usage,Usages),param(Index)
    do
      Intersect #<=> ( Start #=< Index #/\ Index #< Start + SquareSize),Usage #= Intersect * SquareSize
    ),sum(Usages,#=,NumFilledCells).

(请注意,我将第二个不等式改为严格的:方格的末端正好在 Start + SquareSize 之前。)

正如您可能会体验到的,这个公式在减少搜索空间方面非常薄弱。改进它的一种方法(但我自己没有尝试过)是用一些累积约束替换 lines_constraints/4

,

您确定您对数组进行编码的方式会给出独特的结果吗?例如,这两个数组可以编码为 [1,1],[1,1]。 first option

second option

,

由于问题出在正方形的数量上,我将它们固定为尽可能高的(单元格总数除以四,因为它们必须不相交),但允许其宽度/高度等于零,有效不存在,然后允许正方形数限制在零和最大正方形数之间。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。