简体   繁体   English

使用约束编程的方形拼图问题解决方案

[英]Square Puzzle Problem Solution with Constraint Programming

Question: Fill in the grid with squares (of any size) that do not touch or overlap, even at the corners.问题:用不接触或不重叠的正方形(任何大小)填充网格,即使在角落也是如此。 The numbers below and at the right indicate the number of grid squares that are filled in the corresponding column / row.下方和右侧的数字表示填充在相应列/行中的网格方块的数量。

To solve this problem, I applied the following constraints: the placed squares should be disjoint and to make sure the number of grid squares is correct, I constrained the sum of the length of the squares that intersect a given row/column to be equal to that row/column number.为了解决这个问题,我应用了以下约束:放置的正方形应该是不相交的,并且为了确保网格正方形的数量是正确的,我将与给定行/列相交的正方形的长度之和限制为等于该行/列号。

However, the outputed solution is [1, 0, 0, 1] ( [NumSquares, X, Y, SquareSize] ), a single square with length of value one in coordinates (0, 0) and it should be the one depicted in the right image (13 squares with different sizes and coordinates).但是,输出的解决方案是[1, 0, 0, 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, NumSquares),                   
    length(SquareSizes, NumSquares),                

    S is Size - 1,           
                           
    domain(StartsX, 0, S),                         
    domain(StartsY, 0, S),                          
    domain(SquareSizes, 1, Size),                  

    construct_squares(Size, StartsX, StartsY, SquareSizes, Squares), 

    % Constraints

    disjoint2(Squares, [margin(0, 0, 1, 1)]),
    lines_constraints(0, Rows, StartsX, SquareSizes),
    lines_constraints(0, Columns, StartsY, SquareSizes),

    % Solution search

    VarsList = [NumSquares, StartsX, StartsY, 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,
    construct_squares(Size, T1, T2, T3, T4).  

% Rows and columns NumFilledCells cells constraints

lines_constraints(_, [], _, _).

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

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

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

未解决 解决了

The issue is in your line_constraint/4 predicate.问题出在您的line_constraint/4谓词中。 In it, you are posting some clpfd constraints inside a findall/3 .在其中,您在findall/3中发布了一些 clpfd 约束。 This means that those constraints are only valid inside the findall/3 .这意味着这些约束仅在findall/3内有效。 Here is a way to rewrite your predicate that keeps the constraints posted (given that you are using SICStus, I use the do loop style, which is just syntactic sugar around a recursive predicate):这是一种重写谓词以保持发布约束的方法(鉴于您使用的是 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).

(Note that I changed the second inequality to be a strict one: The end of the square is right before Start + SquareSize .) (请注意,我将第二个不等式更改为严格的不等式:正方形的结束就在Start + SquareSize之前。)

As you will probably experience, this formulation is pretty weak in terms of reducing the search space.正如您可能会体验到的那样,这个公式在减少搜索空间方面非常薄弱。 One way to improve it (but I haven't tried it myself) would be to replace the lines_constraints/4 by some cumulative constraints.改进它的一种方法(但我自己没有尝试过)是用一些累积约束替换lines_constraints/4

Are you sure that the way you code the array gives unique results?您确定对数组进行编码的方式会产生独特的结果吗? For example these two arrays can be coded as [1,0,0,1],[1,0,0,1].例如这两个 arrays 可以编码为 [1,0,0,1],[1,0,0,1]。 第一个选项

第二种选择

Since the problem was in the number of squares, I fixed them to be the highest possible (total number of cells divided by four, since they must be disjoint), but allowed its width/height to be equal to zero, effectively not existing and then allowing for the number of squares to be bounded between zero and the maximum number of squares.由于问题在于正方形的数量,我将它们固定为尽可能高的(单元格总数除以四,因为它们必须不相交),但允许其宽度/高度等于零,实际上不存在并且然后允许平方数限制在零和最大平方数之间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM