Résoudre le problème du nombre d'Aristote

21

Le puzzle des nombres d'Aristote est le défi de remplir chacune des 19 cellules dans une grille hexagonale avec un entier unique entre 1 et 19 de sorte que le total le long de chaque axe est de 38.

Vous pouvez imaginer le plateau de jeu comme ceci:

grille d'Aristote

Et le puzzle, en substance, est la solution à l'ensemble des quinze équations suivantes:

((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)

Où chaque variable est un nombre unique dans l'ensemble {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}.

Il existe plusieurs solutions possibles, et il existe 19!des combinaisons possibles d'entiers, de sorte que la force brute naïve ne sera pas pratique.

Règles:

  1. Pas de codage en dur de la réponse ni de recherche de la réponse ailleurs; votre code doit le trouver par lui-même
  2. La vitesse n'a pas d'importance, mais vous devez montrer vos résultats, donc le code qui prend 1000 ans à exécuter ne vous aidera pas
  3. Trouvez toutes les réponses
  4. Traitez les réponses identiques en rotation comme identiques
  5. Déduisez 5% de votre nombre total d'octets si vous produisez les résultats dans un nid d'abeilles attrayant
  6. Le moins d'octets gagne
Michael Stern
la source
Grande question, impatient de trouver une solution.
ProgrammeurDan
Considérez-vous les réponses tournées comme uniques? Par exemple, supposons que a, b, c = 1, 18, 19 indexe une solution particulière, si nous définissons c, g, l = 1, 18, 19 et que toutes les autres valeurs sont "tournées" pour correspondre, considérez-vous cela comme unique Solution?
ProgrammeurDan
@ProgrammerDan Les réponses pivotées sont identiques. Je vais clarifier.
Michael Stern
1
Un hexagone a plus de symétries que de simples rotations. Qu'en est-il des réponses identiques sous une combinaison de rotation et de réflexion?
Peter Taylor
Intéressé de voir une solution à celle-ci en utilisant des cartes auto-organisées.
Ant P

Réponses:

3

Haskell 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}]

Une autre réponse similaire, en utilisant l'arithmétique pour obtenir les hexagones intermédiaires. Contrairement aux autres solutions, je ne teste pas pour ces sommes> 0, tester que les hexs triés sont égaux à la plage [1..19] est suffisant. a, c et h sont limités de sorte que seules les solutions à rotation / miroir uniques sont autorisées. La solution apparaît après quelques secondes, puis il y a une attente d'une minute environ pendant qu'elle décide qu'il n'y en a plus.

Utilisation dans ghci:

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

Édité pour raser quelques caractères. 'y 0 t' produit [1..19].

bazzargh
la source
1
En fait, je fais la même chose dans ma réponse C :) putain comment pourrais-je ne pas voir que Haskell est l'outil parfait pour le travail: P +1
Niklas B.
Je passe à côté de votre x>0chèque, parce que je trie la liste en incluant les négatifs au lieu d'incrémenter un tableau? D'un autre côté, je dois restreindre les plages (my y a b) pour que Haskell fonctionne, ce qui me coûte quelques caractères. Mais il y a forcément un autre langage qui a un type intégré qui me battra de la même façon (en vous regardant, Mathematica).
bazzargh
Oui, le tri en C n'est malheureusement pas aussi simple que dans Haskell. Le problème avec Mathematica est qu'il n'est pas compilé et donc tellement sacrément lent :(
Niklas B.
Je fais toujours ça à Haskell pour m'entraîner, même si une autre langue serait mieux.
bazzargh
En fait, je programme Haskell comme un travail secondaire, donc je suis perplexe à l'idée qu'il ne m'est même pas venu à l'esprit de l'utiliser ici: D C'est un langage vraiment génial, même dans le monde réel / impur
Niklas B.
10

Java (1517 - 75,85) = 1441,15 (1429 - 71,45) = 1357,55 (1325 - 66,25) = 1258,75

C'était amusant.

Imprime toutes les solutions uniques grâce à la mise en miroir et à la rotation, dans un nid d'abeilles agréable (d'où une réduction de 5%)

Durée d'exécution: ~ 0,122 s (122 millisecondes) sur mon ordinateur portable de 4 ans.

Code golfé (le montage a réalisé que je répétais stupidement mes printfs, les a réduits à un seul printf pour un maximum de golf) ( nouveau montage Réduction des appels aux fonctions Set en fonctions plus petites intelligentes, quelques autres micro-optimisations):

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();}}

La force brute est dépassée, mais une utilisation intelligente du fait qu'il n'existe qu'un très petit ensemble de solutions m'a conduit à une réponse basée sur l'itération, où dans chaque boucle de l'itération, je ne considère que les entiers qui n'ont pas encore été "assignés". J'utilise HashSet de Java pour obtenir des recherches O (1) pour les nombres qui ont été utilisés précédemment. Enfin, il existe exactement 12 solutions, mais lorsque vous actualisez la rotation et la mise en miroir, cela se réduit à une seule solution unique, donc lorsque la première solution est rencontrée, je l'imprime et je termine. Consultez mon code moins golfé sur github pour voir un peu plus clairement comment j'aborde cette solution.

Prendre plaisir!

ProgrammerDan
la source
Eh bien, vous vous allongez dans votre spoiler, il existe des solutions plus différentes, donc votre réponse n'est pas valide.
ST3
Forte affirmation, pouvez-vous étayer votre réponse par une réponse personnelle pour le prouver? Je ne suis certainement pas au courant de mensonges intentionnels dans mon spoiler.
ProgrammeurDan
donc quand la première solution est rencontrée, je l'imprime et mets fin à la règle no. 3 raconte raconte pour trouver toutes les réponses. Il y a 19 comme OP l'a dit, je ne sais pas si c'est vraiment 19, mais je me suis déjà 17 heurté à une tâche similaire, alors sachez qu'il y en a plus d'un.
ST3
Vous devez lire mon spoiler entier . J'ai trouvé 12 solutions. Ensuite, vous devez lire l' intégralité des commentaires joints à la question. L'OP dit que les réponses qui sont égales par rapport à la rotation sont équivalentes et doivent être ignorées. Une autre personne a demandé si les réponses égales à la mise en miroir devaient être ignorées. Bien que l'OP n'ait à ce jour pas répondu à cette requête, mon et toutes les autres solutions à ce jour supposent que la réponse est "oui". Par conséquent, ma solution est entièrement complète, parfaitement précise et il n'y a pas de "mensonge" ici. Cependant, si vous souhaitez voir les 12 solutions, supprimez la return;déclaration.
ProgrammeurDan
Enfin, c'est le golf de code. Considérant que l'ajout d'une return;instruction arbitraire augmente la longueur de mon code de 7, il serait insensé pour moi de l'ajouter si la vraie réponse incluait les 12 solutions qui sont simplement des versions tournées / en miroir les unes des autres. Bien que la folie ne puisse pas être exclue, dans ce cas, l'ajout de return;était intentionnel, et comme je l'ai décrit, sur la base de la boîte de dialogue complète des questions et commentaires , que vous devriez prendre soin d'examiner avant de lancer des accusations. Merci!
ProgrammeurDan
8

C, 366 octets ( C ++ 541 450 )

#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);}}

Compilez avec gcc -std=c99 -O3.

Imprime toutes les solutions uniques de rotation modulo et de mise en miroir, au format a b c d ..., une par ligne.

Durée: 0,8 seconde sur mon ordinateur.

Nous énumérons les cellules dans l'ordre h -> c -> s -> a -> l -> q -> e pour une élagage maximal. En fait, la version ci-dessus essaie toutes les 20 ^ 7 affectations pour ces variables. Ensuite, nous pouvons calculer toutes les autres cellules. Il n'y a qu'une seule solution unique de rotation / mise en miroir modulo. Une version C ++ plus ancienne, moins golfée et ~ 20 fois plus rapide (en raison de l'élagage) peut être trouvée sur Github

Niklas B.
la source
J'adore l'approche largement arithmétique ici. Bravo! +1
ProgrammeurDan
1

Matlab: 333 320 caractères

Il s'agit d'une approche assez stupide de force brute qui n'utilise pas la récursivité. Il construit des solutions partielles dans z, qui sont imprimées à la fin. Chaque colonne est une solution; les éléments sont classés az de haut en bas. Le temps d'exécution est de 1 à 2 heures.

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

Exécution depuis Matlab:

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

ans =

    9
   11
   18
   14
    6
    1
   17
   15
    8
    5
    7
    3
   13
    4
    2
   19
   10
   12
   16
intx13
la source