【问题标题】:Programming for Young tableaux年轻画面的编程
【发布时间】:2013-03-20 06:11:53
【问题描述】:

下面是一个奇怪的问题:
我正在我的学校举办解决问题的比赛,他们允许我们使用电脑。因为我是比赛中唯一知道如何编码的人,所以我使用 C 和 Pascal 程序来更快地解决问题。我已经通过伪代码到代码的练习、算法、Collat​​z 猜想验证等来做到这一点。
现在,昨天我正在为下一个挑战(4 月 18 日)进行训练,我看到了一个关于 Young 画面的练习。措辞是这样的(我会尽力从意大利语翻译):
“费雷尔图是分布在一个或多个水平行中的 N 个框的配置,左对齐并配置为使每一行包含的框数与其上的行相同或更少。这些配置也可以通过以下列表来描述盒子的编号,如下图所示:

(来源:olimpiadiproblemsolving.it

Young 画面是由 N 个盒子组成的 Ferrers 图,其中填充了从 1 到 N 的整数。示例:

(来源:olimpiadiproblemsolving.it

如果框中的数字按行和列按升序排序,则该表是“标准”表(例如:第一、第三和第五表)。在标准表格中,第一行的第一个框始终包含 1。N 始终位于图表其中一行的最左边的框中。


问题

考虑一个 [6,3,2,1,1,1] 费雷尔图:
1) 如果第 1 行第 6 个盒子上固定 6,第 1 列最后一个盒子上固定 11,你可以用几种方式完成标准的图表?

2) 如果 7 固定在第 1 行的第 6 个盒子上,而 11 固定在第 1 列的最后一个盒子上,你有几种方法可以以标准的方式完成图表?

3) 如果第 1 行第 6 个盒子上固定 8,第 1 列最后一个盒子上固定 11,你有多少种方式可以用标准方式完成图表?"

我试图用一个填充了这些数字的矩阵和“-1”作为“行结束字符”来编写一个解决方案,但我被卡住了。我如何编码“以各种可能的方式填充它,以便画面是标准的?”。

【问题讨论】:

  • 为此,我认为 Prolog 是比 C 更好的工具选择。
  • 很久没看到这么好的问题了。在这里,投下我今天的最后一票。
  • 嗯...Prolog 是什么?
  • 想一想如何在不实际生成解决方案的情况下计算填充方法的数量。动态编程、记忆和递归将成为你的朋友。由于其他竞争对手没有使用程序,因此必须有一个不涉及大量计算的解决方案。好问题!
  • 绘制画面时,我注意到如果我将绘制它的纸张顺时针旋转 90°,它看起来是一样的。此外,在第一列中,除了 1,6 和 11 之外,可以有 1 到 11 之间的任何数字,在第一行中,除了 1 和 6 之外,可以有 1 到 6 之间的任何数字。并且有 14 个框,因此 N=14。嗯。

标签: c prolog diagram constraint-programming clpfd


【解决方案1】:

这是使用 SWI-Prolog 解决第一个问题的示例解决方案:

:- use_module(library(clpfd)).

tableau(Ts) :-
        Ts = [[A,B,C,_,_,F],
              [G,H,I],
              [J,K],
              [L],
              [M],
              [N]],
        A = 1,
        maplist(ascending, Ts),
        ascending([A,G,J,L,M,N]),
        ascending([B,H,K]),
        C #< I,
        append(Ts, Vs),
        all_different(Vs),
        Vs ins 1..14,
        F = 6,
        N = 11,
        label(Vs).

ascending(Vs) :- chain(Vs, #<).

答案是有两种方法可以完成画面:

?- tableau(Ts), maplist(writeln, Ts).
[1,2,3,4,5,6]
[7,12,13]
[8,14]
[9]
[10]
[11]
    Ts = [[1, 2, 3, 4, 5, 6], [7, 12, 13], [8, 14], [9], [10], [11]] ;
[1,2,3,4,5,6]
[7,12,14]
[8,13]
[9]
[10]
[11]
    Ts = [[1, 2, 3, 4, 5, 6], [7, 12, 14], [8, 13], [9], [10], [11]] ;
false.

【讨论】:

  • 非常感谢!这个工作与 SWIProlog 协商它,我已经学会操纵它来解决 Young 画面的任何问题!再次感谢!
【解决方案2】:

为了解决这个问题,我将使用约束编程 (CP)。 Young 画面实际上是我在学习新的 CP 系统时尝试解决的标准问题之一。以下是迄今为止的实现列表:http://hakank.org/common_cp_models/#youngtableaux

我已经更改了“普通”MiniZinc 模型,并针对您的特定问题添加了一些额外的限制。在此处查看完整模型: http://www.hakank.org/minizinc/young_tableaux_stack_overflow.mzn

(MiniZinc 的级别非常高,很容易解决此类问题。)

关于模型中的表示的简短说明: 对于大小为 n(n 的划分)的问题,框表示为网格(“x”,大小为 n 乘以 n),其值从 1 到 n+1,其中每一行和每一列按升序排序;所以 n+1 排在最后,并作为一个空值。然后处理分区结构(“p”)以符合 Young/Ferrer 结构(详见模型)。

三个问题中的每一个都有两个额外的约束(与问题的标准表述相比):

  • 某个数字应该在第一行的第 6 个框中 添加的约束是 x[1,6] = 6 % 或 7 或 8

  • 并且 11 应该在第一列的最后一个框中 这有点棘手,但我的方式是这样,即 第一列中的 11 应该是小于 n+1 的值中的最后一个, 即列中的所有值都是 n+1:

     exists(j in 1..n) (
          x[j,1] = 11 /\ forall(k in j+1..n) (x[k,1] = n+1)
     )
    

所以,如果我正确理解了这些问题,答案是: 1) 2 个解决方案 2) 10 个解决方案 3) 30 种解决方案

【讨论】:

  • 非常有趣的链接!我从来没有听说过那里提到的任何 CP 系统,或者 CP 本身,但看起来很有趣。我会调查的。谢谢。
  • 对于许多类别的谜题或问题来说,约束传播很重要。当我学习一门新语言时,我通常会移植 Peter Norvig 的Sudoku solver in Python。值得一读,是对约束传播的一个小介绍。
【解决方案3】:

在不使用程序的情况下,我相信 1) 的答案是 2。手动推导可能会导致某人找到算法解决方案。

第一行以 1 开头,以 6 结尾。因此,可以进入第 1 行的数字必须满足这个条件:1

第一列以 1 开头,以 11 结尾。可以进入第一列的数字必须满足类似的条件:1

现在只剩下 3 个数字:12 13 14。在画面的剩余 3 个单元格中排列它们只有两种方法。他们可以安排:

12 13

14

-- 或--

12 14

13

尝试在代码中解决这个问题,可以采用蛮力路线,或者研究约束传播和回溯技术。这就是为什么有人早些时候建议使用 Prolog 的原因。另一种值得关注的语言是 Python。

【讨论】:

  • 我刚刚注意到,正在刷新页面以将其添加到问题中。第一行必须是 1 2 3 4 5 6。第一列必须是 1 ? ? 9 10 11,因为第4行和第5行是1个盒子。 2) 和 3) 也是如此,它们只是将更多可能的数字添加到第一行。您刚刚编写的解决方案有一个问题:在 2) 和 3) 中,您不能将第一列写为 1 7 8 9 10 11,因为 2) 中分配了 7,而 3) 中分配了 8。如果将 2) 中的 7 和 6 以及 3) 中的 6 和 8 反转(也反转 6 和 7 以使第一列为 1 6 7 9 10 11),则 2) 和 3) 的答案也是 2。
  • 这是否意味着在 [6,3,2,1,1,1] 画面中,11 固定在第一列的最后一个框中,并且任何数字
  • 我已经找到了 6 种满足您初始限制的画面解决方案。我正在尝试的画面是:8 在第一行的最后一个单元格中,11 在第一列的最后一个单元格中。很可能有 6 个以上的解决方案,但我在工作中已经到了休息时间的尽头。 :)
  • 好的,我写的作为对此的评论是错误的。谢谢 ;) 另外,要在 C 中完成,我必须编写很多函数,而且我认为这也会非常低效。
【解决方案4】:

这是一个约束逻辑编程问题。使用编程语言 Prolog。带有 clpfd 库的 Sicstus 序言。

考虑这样的布局:

ABCDEF
GHI
JK
L
M
N

--代码--

use_module(library(clpfd)).

all_different([A,B,C,D,E,F,G,H,I,J,K,L,M,N]),
domain([A,B,C,D,E,F,G,H,I,J,K,L,M,N],1,14),
B #> A, C #> B, D #> C, E #> D, F #> E,
G #> A, H #> B, H #> G, I #> G, I #> H,  I #> C,
J #> A, J #> G, 
L #> A, L #> G, L #> J,
M #> A, M #> G, M #> J, M #> L,
N #> A, N #> G, N #> J, N #> L, N #> M.

A=1
F=6
N=11

【讨论】:

  • 我尝试将其复制粘贴到一个文件中并使用 SWIProlog 进行咨询,但它给了我一个意外的文件结束错误。我该怎么办?我尝试谷歌搜索,但没有。 :(
【解决方案5】:

这是著名的 Cormen 书中的一个练习。我发现this resource 对学习这个问题很有帮助,制作这种结构,提取最小元素,保持数据结构不变。

【讨论】:

    猜你喜欢
    • 2018-09-20
    • 2015-07-02
    • 1970-01-01
    • 2020-05-16
    • 2022-07-06
    • 2020-04-07
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    相关资源
    最近更新 更多