Risolvi il problema numerico di Aristotele


21

Il puzzle numerico di Aristotele è la sfida di popolare ciascuna delle 19 celle in una griglia esagonale con un numero intero unico compreso tra 1 e 19 in modo tale che il totale lungo ogni asse sia 38.

Puoi immaginare il tabellone come questo:

griglia di aristotle

E il puzzle, in sostanza, è la soluzione alla seguente serie di quindici equazioni:

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

Dove ogni variabile è un numero univoco nel set {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}.

Esistono molteplici soluzioni possibili e 19!possibili combinazioni di numeri interi, quindi la forza bruta ingenua sarà impraticabile.

Regole:

  1. Non è possibile codificare la risposta o cercare la risposta altrove; il tuo codice deve trovarlo da solo
  2. La velocità non ha importanza, ma devi mostrare i tuoi risultati, quindi il codice che richiede 1000 anni per essere eseguito non ti aiuterà
  3. Trova tutte le risposte
  4. Tratta le risposte identiche in rotazione come identiche
  5. Dedurre il 5% del conteggio totale dei byte se si generano i risultati in un favoloso nido d'ape
  6. Vince il minor numero di byte

Grande domanda, non vedo l'ora di lavorare su una soluzione.
Programmatore

Consideri le risposte ruotate come uniche? Ad esempio, supponiamo che a, b, c = 1, 18, 19 indicizzi una soluzione particolare, se impostiamo c, g, l = 1, 18, 19 e tutti gli altri valori sono "ruotati" in modo che corrispondano, consideri questo univoco soluzione?
Programmatore

@ProgrammerDan Le risposte ruotate sono identiche. Chiarirò.
Michael Stern,

1
Un esagono ha più simmetrie delle semplici rotazioni. Che dire delle risposte identiche in una combinazione di rotazione e riflessione?
Peter Taylor,

Interessato a vedere una soluzione a questo usando mappe auto-organizzanti.
Ant P

Risposte:


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

Un'altra risposta simile, usando l'aritmetica per ottenere gli esagoni intermedi. A differenza delle altre soluzioni, non provo che quelle somme siano> 0, è sufficiente verificare che gli esagoni ordinati siano uguali all'intervallo [1..19]. a, c e h sono limitati in modo che siano consentite solo soluzioni con rotazione / mirroring univoche. La soluzione appare dopo alcuni secondi, quindi c'è un'attesa di circa un minuto mentre decide che non c'è più.

Utilizzo in ghci:

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

A cura di radere alcuni caratteri. 'y 0 t' produce [1..19].


1
In realtà sto facendo la stessa cosa nella mia risposta in C :) accidenti come non potrei vedere che Haskell è lo strumento perfetto per il lavoro: P +1
Niklas B.

Mi manca il x>0controllo, perché ordino l'elenco includendo i negativi invece di incrementare un array? D'altra parte, devo limitare le gamme (mia y a b) per far funzionare Haskell, il che mi costa alcuni caratteri. Ma c'è sicuramente un'altra lingua che ha un tipo integrato che mi batterà lavorando allo stesso modo (guardandoti, Mathematica).
bazzargh,

Sì, purtroppo l'ordinamento in C non è così semplice come in Haskell. Il problema con Mathematica è che non è stato compilato e quindi è così dannatamente lento :(
Niklas B.

Faccio sempre queste cose a Haskell per fare pratica, anche se un'altra lingua sarebbe migliore.
bazzargh,

In realtà programmo Haskell come lavoro secondario, quindi sono sconcertato dal fatto che non mi sia nemmeno venuto in mente di usarlo qui: D È un linguaggio davvero fantastico, anche nel mondo reale / impuro
Niklas B.

10

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

È stato divertente.

Stampa tutte le soluzioni uniche rispetto al mirroring e alla rotazione, in un piacevole nido d'ape (quindi riduzione del 5%)

Durata: ~ 0.122s (122 millisecondi) sul mio laptop di 4 anni.

Codice golf ( modifica realizzato stavo ripetendo stupidamente i miei printfs, li ho ridotti a un singolo printf per il massimo golf) ( nuova modifica Chiamate ridotte per impostare le funzioni in funzioni più piccole intelligenti, alcune altre micro-ottimizzazioni):

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 forza bruta è passe, ma l'uso intelligente del fatto che esiste solo un piccolo insieme di soluzioni mi ha portato a una risposta basata sull'iterazione, dove all'interno di ogni ciclo dell'iterazione considero solo numeri interi che non sono ancora stati "assegnati". Uso Java HashSet per ottenere ricerche O (1) per i numeri che sono stati utilizzati in precedenza. Infine, ci sono esattamente 12 soluzioni, ma quando si scontano sia la rotazione che il mirroring, ciò si riduce a un'unica soluzione unica, quindi quando viene rilevata la prima soluzione, la stampo e la termino. Dai un'occhiata al mio codice meno golfato su github per una visione più chiara di come mi sto avvicinando a questa soluzione.

Godere!


Bene, stai mentendo nel tuo spoiler, ci sono soluzioni più diverse, quindi la tua risposta non è valida.
ST3,

Affermazione forte, puoi supportarlo con una tua risposta per dimostrarlo? Non sono certo a conoscenza di bugie intenzionali nel mio spoiler.
Programmatore

quindi quando viene trovata la prima soluzione, la stampo e concludo la regola n. 3 dice dice di trovare tutte le risposte. Ci sono 19 come ha detto OP, non sono sicuro che siano davvero 19, ma in precedenza mi sono imbattuto in un compito simile, quindi sappi che ce n'è più di uno.
ST3,

Devi leggere tutto il mio spoiler. Ho trovato 12 soluzioni. Quindi devi leggere tutti i commenti allegati alla domanda. L'OP afferma che le risposte che sono uguali rotazione wrt sono equivalenti e dovrebbero essere saltate. Un'altra persona ha chiesto se le risposte uguali al mirroring wrt dovessero essere saltate. Sebbene finora il PO non abbia risposto a questa domanda, sia la mia che tutte le altre soluzioni finora presuppongono che la risposta sia "sì". Quindi, la mia soluzione è completamente completa, completamente accurata e qui non ci sono "bugie". Tuttavia, se desideri vedere tutte e 12 le soluzioni, rimuovi la return;dichiarazione.
Programmatore

Infine, questo è il codice golf. Considerando che l'aggiunta di un'istruzione arbitraria return;aumenta la lunghezza del mio codice di 7, sarebbe folle per me aggiungerlo se la vera risposta includesse tutte le 12 soluzioni che sono semplicemente versioni ruotate / rispecchiate l'una dell'altra. Sebbene la follia non possa essere esclusa, in questo caso, l'aggiunta di è return;stata intenzionale e, come ho descritto, basata sulla finestra di dialogo completa di domande e commenti , che dovresti fare attenzione a rivedere prima di lanciare accuse. Grazie!
Programmatore

8

C, 366 byte ( 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);}}

Compila con gcc -std=c99 -O3.

Stampa tutte le soluzioni uniche modulo rotazione e mirroring, nel formato a b c d ..., uno per riga.

Durata: 0,8 secondi sul mio computer.

Enumeriamo le celle nell'ordine h -> c -> s -> a -> l -> q -> e per la massima potabilità. In effetti la versione precedente prova solo ogni 20 ^ 7 assegnazioni per quelle variabili. Quindi possiamo calcolare tutte le altre celle. Esiste una sola soluzione unica di rotazione / mirroring del modulo. Una versione C ++ più vecchia, meno giocata a golf e ~ 20 volte più veloce (a causa della potatura) è disponibile su Github


Adoro l'approccio ampiamente aritmetico qui. Bravo! +1
Programmatore

1

Matlab: 333 320 caratteri

Questo è un approccio quasi stupido a forza quasi bruta che non usa la ricorsione. Costruisce soluzioni parziali in z, che viene stampato alla fine. Ogni colonna è una soluzione; gli elementi sono elencati az dall'alto verso il basso. Il tempo di esecuzione è di 1-2 ore.

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

In esecuzione da Matlab:

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

ans =

    9
   11
   18
   14
    6
    1
   17
   15
    8
    5
    7
    3
   13
    4
    2
   19
   10
   12
   16
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.