日历拼图的线性规划解法

以带星期的拼图为例,一个符合条件的解应该是如下样子:
在这里插入图片描述

1. 构建0-1矩阵

首先,将问题进行分解,其有10块拼图,每块拼图由最多5个方块组成,每块拼图又有最多8种形态(或状态),分别为:原始、逆时针旋转90°后左右翻转(左下右上45°翻转)、左右翻转、逆时针旋转90°、上下翻转、顺时针旋转90°、旋转180、顺时针旋转90后左右翻转(左上右下45°翻转)。在拼好的状态下,每块拼图的每个方块都有唯一的位置,即行索引和列索引。

由此,我们可以构建一个5维矩阵,其中的每个元素用work[p, n, s, r, c] 表示,即p拼图的第n个方块在第s种形态下是否在第r行第c列,这是一个0-1矩阵,每个元素只有两种取值,即真或假(0或1)。

请注意上面所用的字母,下文中将经常提到,即:

  • p:拼图块
  • n:拼图块的第n个方块
  • s:拼图块所处的形态
  • r:行号
  • c:列号

当然,可能的优化方法是将块拼图的所有47个方块统一编号为0-46,这样就是一个4维矩阵,但是在下步的设置条件环节将更为复杂,我们在此不做讨论。

2. 约束条件设置
  1. 首先,要将拼图块放在底板上,每个位置只能有1个方块(个别位置没有),且这个拼图块(方块)只能处于1种形态。即:在位置[r,c]上所有[p,n,s]位置元素取值的和小于等于1(无法保证等于1,因为指定的日期,即底板内空白的位置是不确定的),当然,因为底板形状不是长方形,在某些位置其应该等于0。

在该条件下,可能有的拼图块取到很多次(有多个位置),有的却并没有被使用。

  1. 其次,需要再添加一个条件,每种拼图块的每个方块号只有1个行号、列号、形态(由于拼图块所含方块数不同,部分拼图块不可选择某些方块号)。即:在[p,n]上所有[r,c,s]位置元素的取值的和等于1,当然,实际不存在的方块号其和为0。

在该条件下,不同的方块可以选择同一个位置。

  1. 另外一个显而易见的条件是,每种拼图块的所有方块均应属于一种形态,毕竟不能把拼图块真的切成方块。即:对每种拼图块的每种形态([p,s]),所有位置上的方块数总和([n,r,c])要么等于0(未使用该形态),要么等于拼图块的方块数。

  2. 在这一步,要把每种拼图块的方块"拼"成其本身的形状。首先确定每种拼图块的一种形态,将其方块进行编号(如0-5),确定0号方块的位置,即可确定其他方块的位置(在0号方块偏移i行j列的位置)。即在某位置,某拼图块的某形态下([r,c,p,s]),0号方块与第n号方块所在元素的和不等于1(为0时,拼图块不在该位置;为2时,拼图块在该位置)。

若假设的形态下0号方块位于(r,c),其他某方块位置为(r+i,c+j),则其他形态下分别为(r+i,c+j)(r+j,c+i)(r+i,c-j)(r+j,c-i)(r-i,c+j)(r-j,c+i)(r-i,c-j)(r-j,c-i)

需要注意的是,如果计算出任一方块的位置索引超出底板范围,则说明该拼图块的0号方块在该形态下不能出现在该位置。

  1. 到此,已经可以与实际一致了,即可以把所有拼图块放入底板了。如果不指定日期,再限制所有表示月份的位置,其所有拼图块的所有方块的形态和为11;所有表示星期的位置,和为6即可。要指定日期,则为指定行号、列号下,其余参数取所有值的元素和为0。

  2. 上面的约束已可以计算出所有结果,但是有冗余,因为某些拼图块“变换形态”后,新形态与原形态是一致的,为消除冗余,可以禁用某些形态,即设置该拼图块的某些形态下,所有方块在所有位置下[n,r,c]元素和为0。

要注意辨别哪些形态是重复的,不同的拼图块重复形态并不一致。

3.求解

该问题属于限制条件优化问题,可以使用google的ortools工具箱中CP-SAT 求解器进行求解。

后记

经测试,计算出1种方案的时间在10-20秒之间(带星期),若取为20秒,也就是说,如果每天只计算1种方案,2小时可算完某1年的所有答案,14小时可算完所有答案。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
05-27
以下是2022年的日历: ``` 一月 二月 三月 Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 1 2 3 4 5 6 1 2 3 4 5 6 3 4 5 6 7 8 9 7 8 9 10 11 12 13 7 8 9 10 11 12 13 10 11 12 13 14 15 16 14 15 16 17 18 19 20 14 15 16 17 18 19 20 17 18 19 20 21 22 23 21 22 23 24 25 26 27 21 22 23 24 25 26 27 24 25 26 27 28 29 30 28 28 29 30 31 四月 五月 六月 Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 3 1 1 2 3 4 5 6 4 5 6 7 8 9 10 2 3 4 5 6 7 8 7 8 9 10 11 12 13 11 12 13 14 15 16 17 9 10 11 12 13 14 15 14 15 16 17 18 19 20 18 19 20 21 22 23 24 16 17 18 19 20 21 22 21 22 23 24 25 26 27 25 26 27 28 29 30 23 24 25 26 27 28 29 28 29 30 七月 八月 九月 Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 3 1 2 3 4 5 6 7 1 2 3 4 4 5 6 7 8 9 10 8 9 10 11 12 13 14 5 6 7 8 9 10 11 11 12 13 14 15 16 17 15 16 17 18 19 20 21 12 13 14 15 16 17 18 18 19 20 21 22 23 24 22 23 24 25 26 27 28 19 20 21 22 23 24 25 25 26 27 28 29 30 31 29 30 31 26 27 28 29 30 十月 十一月 十二月 Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su 1 2 1 2 3 4 5 6 1 2 3 4 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31 ``` 请注意,此日历仅显示公共节假日和星期六/星期日。在某些国家和地区,其他节日和假日可能会影响工作日和休息日的安排。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值