Clingo 中的谜语拼图
Riddle puzzle in clingo
因此在 Dan Finkel 的标签序言 wanted to solve the "the giant cat army riddle" 中(有关拼图的描述,请参见视频/Link)。
因为我想提高答案集编程,所以我特此挑战你比我更有效地解决这个难题。您会找到我的解决方案作为答案。我会接受最快的 运行 答案(除非它使用肮脏的技巧)。
规则:
- 硬编码列表的长度(或类似的东西)算作肮脏的 hack。
- 输出必须在谓词
r/2
中,其中第一个参数是列表的索引,第二个参数是列表的条目。
- 测量的时间是第一个有效答案。
我的第一个尝试是生成数字排列并强制通过 3 个操作(+5
、+7
或 sqrt
)之一连接后继元素。我预定义操作以避免 choosing/counting 问题。不需要测试 <60
,因为操作的输出必须是 0
和 59
之间的数字。生成的列表l/2
被转发到输出r/2
,直到数字14
出现。我想有足够的空间来超越我的解决方案。
num(0..59).
%valid operation pairs
op(N*N,N):- N=2..7.
op(Ori,New):- num(Ori), New = Ori+7, num(New).
op(Ori,New):- num(Ori), New = Ori+5, num(New).
%for each position one number
l(0,0).
{l(T,N):num(N)}==1:-num(T).
{l(T,N):num(T)}==1:-num(N).
% following numbers are connected with an operation until 14
:- l(T,Ori), not op(Ori,New), l(T+1,New), l(End,14), T+1<=End.
% 2 before 10 before 14
:- l(T2,2), l(T10,10), T10<T2.
:- l(T14,14), l(T10,10), T14<T10.
% output
r(T,E):- l(T,E), l(End,14), T<=End.
#show r/2.
第一个答案:
r(0,0) r(1,5) r(2,12) r(3,19) r(4,26) r(5,31) r(6,36) r(7,6)
r(8,11) r(9,16) r(10,4) r(11,2) r(12,9) r(13,3) r(14,10) r(15,15)
r(16,20) r(17,25) r(18,30) r(19,37) r(20,42) r(21,49) r(22,7) r(23,14)
有多个不同长度的可能列表。
num(0..59).
%valid operation pairs
op(N*N,N):- N=2..7.
% no need to add operations that start with 14
op(Ori,New):- num(Ori), New = Ori+7, num(New), Ori!=14.
op(Ori,New):- num(Ori), New = Ori+5, num(New), Ori!=14.
%iteratively create new numbers from old numbers
l(0,0).
{l(T+1,New) : op(Old,New)} = 1 :- l(T,Old), num(T+1), op(Old,_).
%no number twice
:- 2 #sum {1,T : l(T,Value)}, num(Value).
%2 before 10 before 14
%linear encoding
reached(T,10) :- l(T,10).
reached(T+1,10) :- reached(T,10), num(T+1).
:- reached(T,10), l(T,2).
:- l(T,14), l(T+1,_).
%looks nicer, but quadratic
%:- l(T2,2), l(T10,10), T10<T2.
%:- l(T14,14), l(T10,10), T14<T10.
%we must have these three numbers in the list somewhere
:- not l(_,2).
:- not l(_,10).
:- not l(_,14).
#show r(T,V) : l(T,V).
#show.
稍微难看一点的编码可以大大改善基础(这是你的主要问题)。
- 我限制 op/2 不以 14 开头,因为这应该是列表中的最后一个元素
- 我确实迭代地创建了列表,这可能不是很好,但至少对于列表的开头,它已经删除了不可能通过接地达到的值。所以你永远不会有
l(1,33)
或 l(2,45)
等......
当达到值 14 时,列表生成也会停止,因为不再有操作 possible/needed.
- 我还添加了“之前”部分的线性缩放版本,尽管对于这个短列表来说并不是真正必要的(但如果您有长列表,这通常是一个很酷的技巧!)这称为“链接”。
- 另请注意,您的 show 语句非常重要,并且确实创建了一些 constraints/variables。
希望这对您有所帮助,否则您也可以在我们的 potassco 邮件列表中随意提出此类问题;)
因此在 Dan Finkel 的标签序言
因为我想提高答案集编程,所以我特此挑战你比我更有效地解决这个难题。您会找到我的解决方案作为答案。我会接受最快的 运行 答案(除非它使用肮脏的技巧)。
规则:
- 硬编码列表的长度(或类似的东西)算作肮脏的 hack。
- 输出必须在谓词
r/2
中,其中第一个参数是列表的索引,第二个参数是列表的条目。 - 测量的时间是第一个有效答案。
我的第一个尝试是生成数字排列并强制通过 3 个操作(+5
、+7
或 sqrt
)之一连接后继元素。我预定义操作以避免 choosing/counting 问题。不需要测试 <60
,因为操作的输出必须是 0
和 59
之间的数字。生成的列表l/2
被转发到输出r/2
,直到数字14
出现。我想有足够的空间来超越我的解决方案。
num(0..59).
%valid operation pairs
op(N*N,N):- N=2..7.
op(Ori,New):- num(Ori), New = Ori+7, num(New).
op(Ori,New):- num(Ori), New = Ori+5, num(New).
%for each position one number
l(0,0).
{l(T,N):num(N)}==1:-num(T).
{l(T,N):num(T)}==1:-num(N).
% following numbers are connected with an operation until 14
:- l(T,Ori), not op(Ori,New), l(T+1,New), l(End,14), T+1<=End.
% 2 before 10 before 14
:- l(T2,2), l(T10,10), T10<T2.
:- l(T14,14), l(T10,10), T14<T10.
% output
r(T,E):- l(T,E), l(End,14), T<=End.
#show r/2.
第一个答案:
r(0,0) r(1,5) r(2,12) r(3,19) r(4,26) r(5,31) r(6,36) r(7,6)
r(8,11) r(9,16) r(10,4) r(11,2) r(12,9) r(13,3) r(14,10) r(15,15)
r(16,20) r(17,25) r(18,30) r(19,37) r(20,42) r(21,49) r(22,7) r(23,14)
有多个不同长度的可能列表。
num(0..59).
%valid operation pairs
op(N*N,N):- N=2..7.
% no need to add operations that start with 14
op(Ori,New):- num(Ori), New = Ori+7, num(New), Ori!=14.
op(Ori,New):- num(Ori), New = Ori+5, num(New), Ori!=14.
%iteratively create new numbers from old numbers
l(0,0).
{l(T+1,New) : op(Old,New)} = 1 :- l(T,Old), num(T+1), op(Old,_).
%no number twice
:- 2 #sum {1,T : l(T,Value)}, num(Value).
%2 before 10 before 14
%linear encoding
reached(T,10) :- l(T,10).
reached(T+1,10) :- reached(T,10), num(T+1).
:- reached(T,10), l(T,2).
:- l(T,14), l(T+1,_).
%looks nicer, but quadratic
%:- l(T2,2), l(T10,10), T10<T2.
%:- l(T14,14), l(T10,10), T14<T10.
%we must have these three numbers in the list somewhere
:- not l(_,2).
:- not l(_,10).
:- not l(_,14).
#show r(T,V) : l(T,V).
#show.
稍微难看一点的编码可以大大改善基础(这是你的主要问题)。
- 我限制 op/2 不以 14 开头,因为这应该是列表中的最后一个元素
- 我确实迭代地创建了列表,这可能不是很好,但至少对于列表的开头,它已经删除了不可能通过接地达到的值。所以你永远不会有
l(1,33)
或l(2,45)
等...... 当达到值 14 时,列表生成也会停止,因为不再有操作 possible/needed. - 我还添加了“之前”部分的线性缩放版本,尽管对于这个短列表来说并不是真正必要的(但如果您有长列表,这通常是一个很酷的技巧!)这称为“链接”。
- 另请注意,您的 show 语句非常重要,并且确实创建了一些 constraints/variables。
希望这对您有所帮助,否则您也可以在我们的 potassco 邮件列表中随意提出此类问题;)