Questi dadi non sono transitivi?


31

I dadi non transitivi sono simpatici piccoli giocattoli che sfidano la nostra intuizione nella teoria della probabilità. Avremo bisogno di alcune definizioni per questa sfida:

Considera due dadi A e B che vengono lanciati contemporaneamente. Diciamo che A batte B se la probabilità di A che mostra un numero maggiore di B è strettamente maggiore della probabilità di B che mostra un numero più grande di A .

Consideriamo ora un insieme di tre dadi, con le etichette A , B , C . Un tale set di dadi si chiama non transitivo se

  • o A batte B , B batte C e C batte A
  • o C batte B , B batte A e A batte C .

Come uno dei miei esempi preferiti, considera i dadi Grime , che hanno i seguenti lati:

A: 3 3 3 3 3 6
B: 2 2 2 5 5 5
C: 1 4 4 4 4 4

È interessante notare che la media di ogni dado è 3,5, proprio come un dado normale.

Si può dimostrare che:

  • A batte B con una probabilità di 7/12.
  • B batte C con una probabilità di 7/12.
  • C batte A con una probabilità di 25/36.

Ora questi dadi particolari sono ancora più strani. Se tiriamo ogni dado due volte e sommiamo i risultati, l'ordine di quale battito che viene invertito:

  • B batte A con una probabilità di 85/144.
  • C batte B con una probabilità di 85/144.
  • A batte C con una probabilità di 671/1296.

Chiamiamo un set di dadi con questa proprietà Grime-non transitivo .

D'altra parte, se i dadi mantengono il loro ciclo originale quando usano due lanci, li chiamiamo fortemente non transitivi . (Se non esiste alcun ciclo per due lanci, li chiamiamo semplicemente non transitivi .)

La sfida

Dato tre dadi a sei facce, determinare quale delle proprietà sopra questo insieme contiene, e l'uscita di uno dei seguenti stringhe: none, nontransitive, Grime-nontransitive, strongly nontransitive.

È possibile scrivere un programma o una funzione, accettare input tramite STDIN, argomento della riga di comando, argomento prompt o funzione e scrivere il risultato su STDOUT o restituirlo come stringa.

Si può presumere che tutti i lati siano numeri interi non negativi. Non puoi presumere che i lati o i dadi siano in un ordine particolare. Puoi inserire input in qualsiasi elenco o formato stringa conveniente.

Questo è il golf del codice, quindi vince la risposta più breve (in byte).

Casi test

none
1 2 3 4 5 6, 6 5 4 3 2 1, 1 3 5 2 4 6
1 1 1 6 6 6, 4 4 4 5 5 5, 5 5 5 5 5 5
1 1 2 5 6 6, 2 2 3 4 4 6, 2 3 3 4 4 5
0 1 2 3 4 5, 1 1 2 3 3 5, 1 2 2 2 3 5
3 13 5 7 13 7, 5 7 11 5 7 13, 5 9 13 5 7 9

nontransitive
1 2 2 4 6 6, 1 2 3 5 5 5, 2 3 4 4 4 4
1 4 4 4 4 4, 2 2 2 4 5 6, 2 3 3 3 5 5
1 2 1 6 5 6, 3 1 3 6 2 6, 2 4 2 4 4 5
3 4 6 6 7 7, 4 4 4 7 7 7, 5 5 5 5 6 7
2 5 11 11 14 14, 5 5 5 14 14 14, 8 8 8 8 8 17

Grime-nontransitive
3 3 3 3 3 6, 2 2 2 5 5 5, 1 4 4 4 4 4
1 1 4 5 5 5, 2 2 2 3 6 6, 3 3 3 4 4 4
2 1 4 6 4 4, 2 4 5 2 3 5, 3 3 6 3 3 3
11 11 13 15 15 16, 12 12 12 13 16 16, 13 13 13 14 14 14
4 4 7 16 19 19, 4 7 13 13 13 19, 4 10 10 10 16 19

strongly nontransitive
2 2 2 5 5 5, 2 3 3 3 5 5, 1 1 4 5 5 5
2 2 2 3 6 6, 2 2 2 5 5 5, 2 2 4 4 4 5
1 5 1 3 6 5, 6 6 4 2 2 1, 5 3 4 3 4 2
0 0 2 4 4 5, 0 1 1 3 5 5, 1 1 2 3 4 4
1 1 9 17 17 21, 1 5 5 13 21 21, 5 5 13 13 13 17

Se vuoi testare il tuo codice in modo ancora più approfondito, Peter Taylor è stato così gentile da scrivere un'implementazione di riferimento, che ha classificato tutti i ~ 5000 set di dadi con i lati da 1 a 6 e una media di 3,5. Collegamento Pastebin


Mi ero completamente dimenticato dei dadi non transitivi. Grazie :)
npst

Il primo esempio non transitivo è corretto? 1 2 2 4 6 6, 1 2 3 5 5 5, 2 3 4 4 4 4Ricevo A <B 17/36, B> C 19/36, C <A 16/36.
Tobia,

@Tobia Stai dimenticando che i sorteggi sono possibili. Devi anche calcolare la frequenza con cui ogni dado perde contro gli altri e controllare se è inferiore alla probabilità di vincita: Sì A vince contro B con 17/36, ma A perde contro B con solo 16/36, quindi A batte B Allo stesso modo, C vince contro A con 16/36 come hai detto, ma C perde contro A con solo 14/36, quindi C batte A.
Martin Ender

Risposte:


5

Dyalog APL, 107 100 byte

{({+/×+/¨,¨×⍵∘.-¨1⌽⍵}{3≠|a←⍺⍺⍵:1⋄a=b←⍺⍺∘.+⍨¨⍵:2⋄3+a=-b}⍵)⊃(⊂'none'),'strongly '⍬'Grime-',¨⊂'nontransitive'}

{T←{+/×+/¨∊¨×⍵∘.-¨1⌽⍵}⋄3≠|S←T⍵:'none'⋄N←'nontransitive'⋄S=D←T∘.+⍨¨⍵:'strongly ',N⋄S=-D:'Grime-',N⋄N}

(Grazie @Tobia per questa soluzione più semplice, più breve e migliore)

Nozioni di base:

  • assegnazione

  • separatore di istruzioni

  • {} forma lambda

  • ⍺⍵ argomento destro e sinistro

  • A:Bguard ("if Athen return B")

Tè una funzione che restituisce 3 se A batte B, B batte C e C batte A; -3 se è esattamente il contrario; e qualcosa nel mezzo. In dettaglio:

  • 1⌽⍵ è l'una rotazione di . Se è ABC, la rotazione è BCA.

  • ∘.-calcola una tabella di sottrazione tra due vettori ( 1 2...10 ∘.× 1 2...10sarebbe la tabella di moltiplicazione che conosciamo dalla scuola). Lo applichiamo tra ciascuno (¨ elemento ) di e l'elemento corrispondente in 1⌽⍵.

  • × signum di tutti i numeri nelle tabelle di sottrazione

  • ∊¨ appiattire ogni tavolo

  • +/¨e sommalo. Ora abbiamo tre numeri che rappresentano i saldi: il numero di vincite meno i casi perdenti per ciascuno di A vs B, B vs C, C vs A.

  • × segno di quelli

  • +/ somma

Quindi gestire le custodie a turno:

  • 3≠|S←T⍵:'none' Se T⍵ il valore assoluto non è 3, restituisce "nessuno"

  • N←'nontransitive' avremo bisogno di questa parola molto

  • S=D←T∘.+⍨¨⍵:'strongly ',Ncalcola le Tcoppie di dadi ( ∘.+⍨¨⍵← → ⍵((∘.+)¨)⍵) e ritorna "fortemente ..." se le stesse relazioni tra ABC sono ancora valide

  • S=-D:'Grime-',N ⍝ "Grime" se le relazioni sono nelle direzioni opposte

  • N se tutto il resto fallisce, solo "non transitivo"


1
Mi hai battuto sul tempo! Stavo lavorando su questo problema 3 giorni fa, ma poi ho smesso di scrivere la mia risposta. È comunque troppo simile al tuo, quindi lo posterò qui. È un po 'più corto a 100 caratteri:{T←{+/×+/¨∊¨×⍵∘.-¨1⌽⍵}⋄3≠|S←T⍵:'none'⋄N←'nontransitive'⋄S=D←T∘.+⍨¨⍵:'strongly ',N⋄S=-D:'Grime-',N⋄N}
Tobia,

@ MartinBüttner: il termine corretto nel titolo è "caratteri", poiché la quantità di byte varierà a seconda del set di caratteri utilizzato per codificare i simboli APL. Tradizionalmente venivano appena codificati nella metà superiore di byte a 8 bit, dopo ASCII. Oggi usiamo UTF-8, ma i vecchi set di caratteri sono ancora utili ... principalmente per ridurre il conteggio dei byte al conteggio dei caratteri durante il golf!
Tobia,

@Tobia Nel codice golf briscola più corta prima, quindi vinci! Non ho molta familiarità con l'etichetta del golf, ma penso che dovresti pubblicarlo come risposta separata in quanto è sostanzialmente diverso e ci sei arrivato in modo indipendente.
ngn

@Tobia Preferisco contare anche i caratteri, ma se è implicita la codifica classica, allora byte = caratteri, quindi forse non importa molto come li chiamiamo ...
ngn

@Tobia Beh, è ​​sicuramente inutile fornire il conteggio dei personaggi in una sfida che segna per byte. Tuttavia, nessuno ha mai detto che stiamo segnando in byte UTF-8. In effetti il tag wiki dice esplicitamente che una diversa codifica esistente può essere utilizzata per caratteri al di fuori dell'intervallo ASCII. E APL ha una sua codepage, quindi l'intero set di caratteri si adatta a un byte. La politica su PPCG è quella di utilizzare questa tabella codici per contare APL - non è giusto punire APL per essere più vecchi di ASCII.
Martin Ender,

13

Python 2, 269

Ecco una simpatica piccola espressione che valuta una funzione. Accetta tre elenchi di numeri interi. Supera tutti i casi di test.

lambda A,B,C,w=lambda A,B:cmp(sum(cmp(a,b)for a in A for b in B),0),x=lambda A,B:cmp(sum(cmp(a+c,b+d)for a in A for b in B for c in A for d in B),0): (w(A,B)==w(B,C)==w(C,A)!=0)*((x(A,B)==x(B,C)==x(C,A))*["","strongly ","Grime-"][x(A,B)*w(A,B)]+"nontransitive")or"none"

2

J - 311 257 byte

Aggiornamento (13 gennaio 2015):

g=:4 :'(+/,x>/y)>+/,y>/x'
h=:4 :'(,+/~x)g,+/~y'
f=: 3 :0
'a b c'=:y
if. (b g a)*(c g b)*a g c do.
a=.2{y
c=.0{y
end.
'none'([`]@.((a g b)*(b g c)*c g a))((''([`]@.((b h a)*(c h b)*a h c))'Grime-')([`]@.((a h b)*(b h c)*c h a))'strongly '),'nontransitive'
)

Spiegazione: Utilizzando Gerunds, semplifica le if.s in @.s.

Versione precedente:

Prima prova sia a programmare in J che a golf.

g=:4 :'(+/,x>/y)>+/,y>/x'
h=:4 :'(,+/~x)g,+/~y'
f=: 3 :0
'a b c'=:y
if. (b g a)*(c g b)*a g c do.
a=.2{y
c=.0{y
end.
if. (a g b)*(b g c)*c g a do.
if. (a h b)*(b h c)*c h a do.
'strongly nontransitive'
elseif. (b h a)*(c h b)*a h c do.
'Grime-nontransitive'
elseif. do.
'nontransitive'
end.
else.
'none'
end.
)

Eseguilo usando una sintassi simile alla seguente (spazi extra per maggiore chiarezza):

f 3 6 $          1 1 9 17 17 21, 1 5 5 13 21 21, 5 5 13 13 13 17

Spiegazione:

gè definito come un diad che prende due matrici che dice se il primo dado batte il secondo dado
hè definito come un diad che prende due matrici che dice se il lancio due volte e sommando, il primo dado batte il secondo
f è una monade che prende un tavolo e restituisce una stringa con il risposta esatta

Modifica: correggi un errore nella condizione Grime non transitoria (sostituendo ,con *)


Mi piacerebbe qualsiasi suggerimento per il miglioramento. :)
Jay Bosamiya,

@ MartinBüttner, inizialmente l'avevo provato, ma non sapevo concatenarmi su più righe (o frasi, come è noto in J) senza aumentare la lunghezza del codice molto di più ... conoscere i "gerundi" mi ha portato a creare il molte frasi in una che finisce anche per abbreviare il codice ...
Jay Bosamiya,

1

Pyth 129 133

Lmsd^b2Msmsm>bkGHDPNK-ghNeNgeNhNR?^tZ<KZKZAGHmsdCm,PkP,yhkyekm,@Qb@QhbUQ?"none"|!G%G3s[*!+GH"Grime-"*qGH"strongly ""nontransitive

Provalo qui , o almeno potresti, ma all'online evalsembra che non piacciano gli elenchi di elenchi :( Se vuoi provarlo lì, archivia manualmente un elenco di 3 dadi in una variabile non utilizzata dal programma e poi sostituisci tutte le istanze di Qcon quella variabile. Un'inizializzazione di esempio:

J[[3 3 3 3 3 6)[2 2 2 5 5 5)[1 4 4 4 4 4))

Questo supera tutti i casi di test di Martin, non ho il cuore passare attraverso tutti i casi di Peter: P

Spiegazione (questo sarà un doozy)

Lmsd^b2

Abbastanza semplice, rende una funzione yche restituisce la somma di ogni coppia cartesiana di valori in un iterabile. Equivalente a: def y(b):return map(lambda d:sum(d),product(b,repeats=2)). Questo è usato per creare matrici a più facce che simulano il lancio delle matrici normali due volte.

Msmsm>bkGH

Definisce una funzione gdi 2 argomenti che restituisce quante volte un dado batte un altro. Equivalente a def g(G,H):return sum(map(lambda k:sum(map(lambda b:b>k,G)),H).

DPNK-ghNeNgeNhNR?^tZ<KZKZ

Definisce una funzione Pche prende un elenco di due dadi come argomento. Questo restituisce -1 se il primo dado "perde", 0 per un pareggio e 1 se il primo dado "vince". Equivalente a:

def P(N):
 K=g(N[0],N[-1]) - g(N[-1],N[0])
 return -1**(K<0) if K else 0

Gli AGHassegnamenti si comportano come un'assegnazione di 2 tuple in pitone. EssenzialmenteG,H=(result)

msdCm,PkP,yhkyekm,@Qb@QhbUQ

Andando a spiegare al contrario attraverso le mappe. m,@Qb@QhbUQscorre sopra b = 0..2 e genera 2 tuple di dadi con indice b e indice b + 1. Questo ci dà i dadi (A, B), (B, C), (C, A) (pyth modifica automaticamente gli indici in base alla lunghezza della lista).

Il prossimo, m,PkP,yhkyek scorre il risultato della mappa precedente, con ogni coppia di dadi che viene memorizzata in k su ogni corsa. Restituisce tuple(P(k),P(tuple(y(k[0]),y(k[-1]))))per ogni valore. Questo si riduce a `((A batte B ?, 2 * A batte 2 * B), (B batte C ?, 2 * B batte ..)).

Finalmente, msdC somma i valori della mappa precedente dopo che è stata zippata. La zip causa tutti i valori dei "battiti" dei singoli dadi nella prima tupla e i valori dei doppi dadi nella seconda.

?"none"|!G%G3s[*!+GH"Grime-"*qGH"strongly ""nontransitive

Una cosa grossolana che stampa i risultati. Se G è 0 o non divisibile per 3, questo catture bot +/- 3, ( |!G%G3), stampe none, altrimenti stampa la somma della lista follwing: [not(G+H)*"Grime",(G==H)*"strongly ","nontransitive"]. Penso che i booleani siano abbastanza esplicativi per quanto riguarda le definizioni nella domanda. Si noti che G non può essere zero qui, poiché viene rilevato dal controllo precedente.


1

J (204)

Troppo a lungo, probabilmente potrebbe essere giocato a golf molto avendo un sistema più efficiente per scegliere la corda giusta.

f=:3 :'(<,>)/"1+/"2>"1,"2(<,>)/L:0{(,.(1&|.))y'
n=:'nontransitive'
d=:3 :0
if.+/*/a=.f y do.+/*/b=.f<"1>,"2+/L:0{,.~y if.a-:b do.'strongly ',n elseif.a-:-.b do.'Grime-',n elseif.do.n end.else.'none'end.
)

1

Matlab (427)

Non è così corto e sono sicuro che può essere giocato a golf molto di più, ho appena provato a risolvere questa sfida perché pensavo fosse un compito molto divertente, quindi grazie @ MartinBüttner per aver creato questa sfida!

a=input();b=input();c=input();
m = 'non';l=@(a)ones(numel(a),1)*a;n=@(a,b)sum(sum(l(a)>l(b)'));g=@(a,b)n(a,b)>n(b,a);s=@(a,b,c)sum([g(a,b),g(b,c),g(c,a)]);
x=s(a,b,c);y=s(a,c,b);if x~=3 && y~=3;m=[m,'e'];else m=[m,'transitive'];o=ones(6,1);a=o*a;a=a+a';a=a(:)';b=o*b;b=b+b';b=b(:)';c=o*c;c=c+c';c=c(:)';u=s(a,b,c);
v=s(a,c,b);if u==3|| v==3;if x==3&&u==3 || y==3&&v==3 m=['strongly ',m];else m=['Grime-',m];end;end;end;disp(m);

Qui il codice integrale con alcuni commenti se vuoi provare a capire cosa sta succedendo. Ho incluso alcuni casi di test di lepre ed escluso i comandi di input:

%nontransitive
% a = [1 2 2 4 6 6];
% b = [1 2 3 5 5 5];
% c = [2 3 4 4 4 4];

%none
% a = [1 2 3 4 5 6];
% b = [6 5 4 3 2 1];
% c = [1 3 5 2 4 6];

%grime nontransitive
% a = [3 3 3 3 3 6];
% b = [2 2 2 5 5 5];
% c = [1 4 4 4 4 4];

%strongly nontransitive
% a = [2 2 2 5 5 5];
% b = [2 3 3 3 5 5];
% c = [1 1 4 5 5 5];

m = 'non';

l=@(a)ones(numel(a),1)*a;
n=@(a,b)sum(sum(l(a)>l(b)'));
%input as row vector, tests whether the left one beats the right one:
g=@(a,b)n(a,b)>n(b,a);
s=@(a,b,c)sum([g(a,b),g(b,c),g(c,a)]);
%if one of those x,y has the value 3, we'll have intransitivity
x=s(a,b,c); 
y=s(a,c,b);
if x~=3 && y~=3 %nontransitive
    m=[m,'e'];
else %transitive
    m=[m,'transitive'];
    o=ones(6,1);
    a=o*a;a=a+a';a=a(:)'; %all possible sums of two elements of a
    b=o*b;b=b+b';b=b(:)';
    c=o*c;c=c+c';c=c(:)';
    u=s(a,b,c);
    v=s(a,c,b);

    %again: is u or v equal to 3 then we have transitivity
    if u==3 || v==3 %grime OR strongly
        % if e.g. x==3 and u==3 then the 'intransitivity' is in the same
        % 'order', that means stronlgy transitive
        if x==3 && u==3 || y==3 && v==3%strongly
            m=['strongly ',m];
        else %grime
            m=['Grime-',m];
        end   
    end
end

disp(m);

Non è più breve se leggi un array input()e poi assegni i tre elementi a,b,c? Inoltre, si prega di utilizzare le stringhe esatte nelle specifiche ( none, nontransitive, e capitalizzati Grime) ... dovrebbe probabilmente anche risparmiare byte.
Martin Ender,

Sì, questo sarebbe probabilmente più breve, ci darò un'occhiata. Le stringhe saranno esattamente quelle in cui ho appena rimosso i dispcomandi nella versione lunga, erano solo per testare il programma, ma il messaggio finale è archiviato m. E ho corretto il G.
Flawr

0

JavaScript - 276 byte

function(l){r=function(i){return l[i][Math.random()*6|0]};p=q=0;for(i=0;j=(i+1)%3,i<3;++i)for(k=0;k<1e5;++k){p+=(r(i)>r(j))-(r(i)<r(j));q+=(r(i)+r(i)>r(j)+r(j))-(r(i)+r(i)<r(j)+r(j))}alert((a=Math.abs)(p)>5e3?((a(q)>5e3?p*q>0?'strongly ':'Grime-':'')+'nontransitive'):'none')}

Non sono molto bravo nelle probabilità, quindi per essere sicuro dei miei risultati, preferisco lanciare i dadi centinaia di migliaia di volte.

L'espressione restituisce una funzione, che dovrebbe essere chiamata con un solo argomento: una matrice di tre matrici di numeri interi. Controlla il violino per poter eseguire il codice da solo.

Ecco la versione ungolfed:

function (diceList) {
    var getRandomValue = function (idDie) {
        return diceList[idDie][Math.floor(Math.random() * 6)];
    };

    var probabilitySimpleThrow = 0;
    var probabilityDoubleThrow = 0;

    for (var idDieA = 0; idDieA < 3; ++idDieA)
    {
        var idDieB = (idDieA + 1) % 3;
        for (var idThrow = 0; idThrow < 1e5; ++idThrow)
        {
            probabilitySimpleThrow += getRandomValue(idDieA) > getRandomValue(idDieB);
            probabilitySimpleThrow -= getRandomValue(idDieA) < getRandomValue(idDieB);

            probabilityDoubleThrow += getRandomValue(idDieA) + getRandomValue(idDieA) > getRandomValue(idDieB) + getRandomValue(idDieB);
            probabilityDoubleThrow -= getRandomValue(idDieA) + getRandomValue(idDieA) < getRandomValue(idDieB) + getRandomValue(idDieB);
        }
    }

    if (Math.abs(probabilitySimpleThrow) > 5e3) {
        if (Math.abs(probabilityDoubleThrow) > 5e3) {
            if (probabilitySimpleThrow * probabilityDoubleThrow > 0) {
                var result = 'strongly ';
            }
            else {
                var result = 'Grime-';
            }
        }
        else {
            var result = '';
        }

        result += 'nontransitive';
    }
    else {
        var result = 'none';
    }

    alert(result);
}

Hm, non penso che questo sia davvero nello spirito della sfida. Fondamentalmente l'hai trasformato da una sfida della teoria della probabilità in una sfida statistica. ;) ... Invece di lanci casuali, potresti semplicemente enumerare tutti i lanci possibili esattamente una volta. Ciò ti darebbe i risultati esatti (e funzionerebbe molto più velocemente).
Martin Ender,

Controllerò se questo porta a uno script più conciso. Grazie per il tuo consiglio :).
Blackhole,
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.