解决亚里士多德的数问题


21

亚里士多德(Aristotle)的数字难题是向六边形网格中的19个单元中的每个单元填充一个介于1到19之间的唯一整数,以使沿每个轴的总数为38的挑战。

您可以像这样绘制游戏板:

亚里士多德网格

本质上,这个难题是对以下十五个方程组的解决方案:

((a + b + c) == 38 && (d + e + f + g) == 38 && (h + i + j + k + l) == 
   38 && (m + n + o + p) == 38 && (q + r + s) == 38 && (a + d + h) == 
   38 && (b + e + i + m) == 38 && (c + f + j + n + q) == 
   38 && (g + k + o + r) == 38 && (l + p + s) == 38 && (c + g + l) == 
   38 && (b + f + k + p) == 38 && (a + e + j + o + s) == 
   38 && (d + i + n + r) == 38 && (h + m + q) == 38)

其中每个变量是集合中的唯一数字{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}

有多种可能的解决方案,并且19!可能是整数的组合,因此幼稚的蛮力将是不切实际的。

规则:

  1. 无需对答案进行硬编码或在其他地方查找答案;您的代码需要自行查找
  2. 速度无关紧要,但是您必须显示结果,因此运行1000年的代码将无济于事
  3. 找到所有答案
  4. 将轮换下相同的答案视为相同
  5. 如果以有吸引力的蜂窝形式输出结果,请减去总字节数的5%
  6. 最少的字节数获胜

很好的问题,期待着解决的办法。
ProgrammerDan

您是否认为轮换答案是唯一的?例如,假设a,b,c = 1、18、19索引是一个特定的解决方案,如果我们将c,g,l = 1、18、19设置为“旋转”以匹配所有其他值,您是否认为这是唯一的解?
ProgrammerDan

@ProgrammerDan旋转答案相同。我会澄清。
2014年

1
六边形的对称性不仅仅是旋转。在旋转和反思的结合下,相同的答案又如何呢?
彼得·泰勒

感兴趣的是使用自组织映射来解决这一问题。
Ant P

Answers:


3

哈斯克尔295 289

import Data.List
t=38
y a b=[max(19-b)(a+1)..19]
w=y 0 t
x=filter((==w).sort)$[[a,b,c,d,e,f,g,h,i,t-a-e-o-s,k,l,m,t-d-i-r,o,p,q,r,s]|a<-[1..14],c<-y a a,l<-y a c,s<-y a l,q<-y a s,h<-y c q,e<-w,let{f=t-g-e-d;i=t-b-e-m;o=t-r-k-g;k=t-p-f-b;b=t-a-c;g=t-l-c;p=t-l-s;r=t-q-s;m=t-q-h;d=t-a-h}]

另一个类似的答案,使用算术运算得出中间十六进制。与其他解决方案不同,我不测试那些总和> 0,测试排序的十六进制等于范围[1..19]就足够了。a,c和h受限制,因此仅允许唯一旋转/镜像的解决方案。几秒钟后,解决方案出现,然后等待一分钟左右,直到它决定不再可用。

ghci中的用法:

ghci> x
[[3,19,16,17,7,2,12,18,1,5,4,10,11,6,8,13,9,14,15]]

编辑以刮除一些字符。“ y 0 t”产生[1..19]。


1
实际上,我在C答案中也做同样的事情:)该死,我怎么看不到Haskell是完成工作的理想工具:P +1
Niklas B.

我错过了您的x>0支票,因为我对包括负数的列表进行排序而不是对数组进行递增?另一方面,我必须限制范围(my y a b)才能让Haskell执行,这要花我一些字符。但是肯定会有另一种具有内置语言的语言会以相同的方式击败我(Mathematica,看着您)。
bazzargh 2014年

是的,不幸的是,使用C进行排序并不像在Haskell中那样简单。Mathematica的问题在于它没有被编译,因此太慢了:(
Niklas B.

我总是在Haskell中进行练习,即使使用另一种语言也会更好。
bazzargh 2014年

我其实编程哈斯克尔作为副业,所以我在那压根没想到要在这里使用它难倒:d这是一个真正伟大的语言,即使在现实/不纯世界
尼克拉斯B.

10

Java (1517-75.85 )= 1441.151429-71.45)= 1357.55(1325-66.25)= 1258.75

很好玩

以令人愉快的蜂窝状打印所有独特的解决方案,包括镜像和旋转功能(因此减少了5%)

运行时间:4岁的笔记本电脑上约为0.122秒(122毫秒)。

打高尔夫球的代码(编辑意识到我是在愚蠢地重复我的printfs,将它们减少为单个printf以最大程度地打高尔夫球)(新编辑将对Set函数的调用减少为聪明的较小函数,还有一些其他的微优化):

import java.util.*;class A{boolean c(Set<Integer>u,int z){return!u.contains(z);}Set<Integer>b(Set<Integer>c,int...v){Set<Integer>q=new HashSet<Integer>(c);for(int x:v)q.add(x);return q;}void w(){Set<Integer>U,t,u,v,w,y,z;int a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,X,Z;X=20;Z=38;for(a=1;a<X;a++)for(b=1;b<X;b++)if(b!=a)for(c=1;c<X;c++)if(c!=a&&c!=b&&a+b+c==Z){U=b(new HashSet<Integer>(),a,b,c);for(d=1;d<X;d++)if(c(U,d))for(h=1;h<X;h++)if(h!=d&&c(U,h)&&a+d+h==Z){t=b(U,a,b,c,d,h);for(m=1;m<X;m++)if(c(t,m))for(q=1;q<X;q++)if(q!=m&&c(t,q)&&h+m+q==Z){u=b(t,m,q);for(r=1;r<X;r++)if(c(u,r))for(s=1;s<X;s++)if(s!=r&&c(u,s)&&q+r+s==Z){v=b(u,r,s);for(p=1;p<X;p++)if(c(v,p))for(l=1;l<X;l++)if(l!=p&&c(v,l)&&s+p+l==Z){w=b(v,p,l);for(g=1;g<X;g++)if(c(w,g)&&l+g+c==Z)for(e=1;e<X;e++)if(e!=g&&c(w,e))for(f=1;f<X;f++)if(f!=e&&f!=g&&c(w,f)&&d+e+f+g==Z){y=b(w,g,e,f);for(i=1;i<X;i++)if(c(y,i))for(n=1;n<X;n++)if(n!=i&&c(y,n)&&d+i+n+r==Z&&b+e+i+m==Z){z=b(y,i,n);for(o=1;o<X;o++)if(c(z,o))for(k=1;k<X;k++)if(k!=o&&c(z,k)&&m+n+o+p==Z&&r+o+k+g==Z&&b+f+k+p==Z)for(j=1;j<X;j++)if(c(z,j)&&j!=o&&j!=k&&a+e+j+o+s==Z&&c+f+j+n+q==Z&&h+i+j+k+l==Z){System.out.printf("%6d%4d%4d\n\n%4d%4d%4d%4d\n\n%2d%4d%4d%4d%4d\n\n%4d%4d%4d%4d\n\n%6d%4d%4d\n\n",a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s);return;}}}}}}}}}public static void main(String[]a){(new A()).w();}}

蛮力是过去的,但是聪明地利用了只有极少数解的事实这一事实使我得出了一个基于迭代的答案,其中在迭代的每个循环中,我只考虑尚未“赋值”的整数。我利用Java的HashSet对先前使用的数字进行O(1)查找。最后,恰好有12个解决方案,但是当您同时减少旋转和镜像时,这将减少为一个唯一的解决方案,因此当遇到第一个解决方案时,我将其打印并终止。在github上查看我不太喜欢的代码,以更清晰地了解我如何实现此解决方案。

请享用!


好吧,您躺在扰流板上,还有更多不同的解决方案,因此您的答案无效。
ST3 2014年

有力的主张,您可以用自己的答案来证明它吗?我当然不知道扰流板有任何故意的谎言。
程序员

因此,当遇到第一个解决方案时,我将其打印出来并终止规则编号。3告诉告诉找到所有答案。正如OP所说,那里有19个,不确定是否真的是19个,但是我之前也遇到过类似的任务,所以知道还有一个以上的任务。
2014年

您需要阅读我的整个剧透。我找到了12个解决方案。然后,您需要阅读问题所附的全部注释。OP认为轮换相等的答案是等效的,应该跳过。另一个人询问是否应跳过与镜像相等的答案。尽管OP迄今尚未回复此查询,但我的解决方案和迄今为止的所有其他解决方案都假定答案为“是”。因此,我的解决方案是完全完整的,完全准确的,这里没有“谎言”。但是,如果您想查看所有12个解决方案,请删除该return;语句。
程序员

最后,这是代码高尔夫。考虑添加一个任意return;语句会使我的代码长度增加7,如果真正的答案包括所有12个彼此简单旋转/镜像的解决方案,那么添加它就太疯狂了。尽管不能排除精神错乱,但在这种情况下,return;有意添加,并且正如我所描述的那样,基于完整的“问题和评论”对话框,您应该谨慎对待,然后再提出指控。谢谢!
程序员

8

C,366字节(C ++ 541450

#define R(i)for(int i=19;i;--i)
#define X(x)if(x>0&&!V[x]++)
#define K(X)X(a)X(b)X(c)X(d)X(e)X(f)X(g)X(h)X(i)X(j)X(k)X(l)X(m)X(n)X(o)X(p)X(q)X(r)X(s)
Q(x){printf("%d ",x);}
T=38,V[99];main(){R(h)R(c)R(s)R(a)R(l)R(q)R(e){int d=T-a-h,b=T-a-c,g=T-c-l,p=T-l-s,r=T-q-s,m=T-h-q,f=T-g-e-d,i=T-b-e-m,n=T-d-i-r,o=T-p-n-m,k=T-g-o-r,j=T-h-i-k-l;R(C)V[C]=0;K(X)K(+Q),exit(0);}}

用编译gcc -std=c99 -O3

a b c d ...每行一个的格式打印所有唯一的模旋转和镜像解决方案。

运行时间:在我的计算机上为0.8秒。

为了最大可修剪性,我们以h-> c-> s-> a-> l-> q-> e的顺序枚举单元格。实际上,以上版本仅尝试为这些变量每20 ^ 7个分配。然后,我们可以计算所有其他单元格。模数旋转/镜像只有一个唯一的解决方案。可以在Github上找到较旧的,打高尔夫球较少且快约20倍的C ++版本(由于修剪)


我喜欢这里的算术方法。太棒了!+1
ProgrammerDan

1

Matlab:333320个字符

这是一种非常愚蠢的近乎暴力的方法,不使用递归。它在中建立了部分解决方案z,该解决方案最后被打印出来。每列都是一个解决方案。元素从上到下以az列出。运行时间为1-2小时。

z=[];
a='abc adh hmq qrs spl lgc defg beim mnop dinr rokg pkfb hijkl aejos cfjnq';while a[k,a]=strtok(a);n=length(k);x=nchoosek(1:19,n)';s=[];for t=x(:,sum(x)==38)s=[s,perms(t)'];end
m=0.*s;m(19,:)=0;m(k(1:n)-96,:)=s(1:n,:);y=[];for p=m for w=z m=[];l=w.*p~=0;if p(l)==w(l) y(:,end+1)=w+p.*(~l);end
end
end
z=[m,y];end
z

从Matlab内部运行:

>> aristotle;
>> z(:,1)

ans =

    9
   11
   18
   14
    6
    1
   17
   15
    8
    5
    7
    3
   13
    4
    2
   19
   10
   12
   16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.