Esses dados não são transitivos?

31

Dados não-transitivos são pequenos brinquedos que desafiam nossa intuição na teoria das probabilidades. Precisamos de algumas definições para este desafio:

Considere dois dados A e B que são lançados ao mesmo tempo. Dizemos que um bate B se a probabilidade de A mostrando um número maior do que B é estritamente maior do que a probabilidade de B mostrando um número maior do que um .

Agora, considere um conjunto de três dados, com rótulos A , B , C . Esse conjunto de dados é chamado de não-transitivo se

  • ou A vence B , B vence C e C vence A
  • ou C bate B , B bate Um e um bate C .

Como um dos meus exemplos favoritos, considere os dados do Grime , que têm os seguintes lados:

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

Curiosamente, a média de cada dado é 3,5, assim como um dado regular.

Pode-se mostrar que:

  • A vence B com uma probabilidade de 7/12.
  • B vence C com uma probabilidade de 7/12.
  • C bate A com uma probabilidade de 25/36.

Agora, esses dados em particular são ainda mais estranhos. Se rolarmos cada dado duas vezes e somarmos os resultados, cuja ordem é melhor que a invertida:

  • B vence A com uma probabilidade de 85/144.
  • C bate B com uma probabilidade de 85/144.
  • A bate C com uma probabilidade de 671/1296.

Vamos chamar um conjunto de dados com essa propriedade Grime-não-transitiva .

Por outro lado, se os dados mantêm seu ciclo original ao usar dois arremessos, os chamamos de fortemente não-transitivos . (Se não houver ciclo para dois lançamentos, simplesmente os chamamos de não - transitivos .)

O desafio

Dado três dados de seis lados, que determinam as propriedades acima Este conjunto tem, e uma das seguintes cadeias de saída: none, nontransitive, Grime-nontransitive, strongly nontransitive.

Você pode escrever um programa ou função, receber entrada via STDIN, argumento de linha de comando, prompt ou argumento de função e gravar o resultado em STDOUT ou retorná-lo como uma string.

Você pode assumir que todos os lados são números inteiros não negativos. Você não pode assumir que os lados ou os dados estão em uma ordem específica. Você pode receber entradas em qualquer lista conveniente ou formato de sequência.

Isso é código de golfe, então a resposta mais curta (em bytes) vence.

Casos de teste

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 você quiser testar seu código ainda mais detalhadamente, Peter Taylor teve a gentileza de escrever uma implementação de referência, que classificou todos os ~ 5000 conjuntos de dados com os lados 1 a 6 e uma média de 3,5. Link Pastebin

Martin Ender
fonte
Eu tinha me esquecido totalmente dos dados não transitivos. Obrigado :)
npst
O primeiro exemplo não traduzido está correto? 1 2 2 4 6 6, 1 2 3 5 5 5, 2 3 4 4 4 4Estou recebendo A <B 17/36, B> C 19/36, C <A 16/36.
Tobia
@Tobia Você está esquecendo que os sorteios são possíveis. Você também precisa descobrir quantas vezes cada dado perde contra os outros e verificar se essa é menor que a probabilidade de ganhar: Sim A vence contra B com 17/36, mas A perde contra B com apenas 16/36, então A vence B Da mesma forma, C vence contra A com 16/36, como você disse, mas C perde contra A com apenas 14/36, então C vence A.
Martin Ender

Respostas:

5

Dyalog APL, 107 100 bytes

{({+/×+/¨,¨×⍵∘.-¨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}

(Obrigado à Tobia por esta solução mais simples, mais curta e melhor)

Noções básicas:

  • tarefa

  • separador de instruções

  • {} forma lambda

  • ⍺⍵ argumento esquerdo e direito

  • A:Bguarda ("se Aentão retornar B")

Té uma função que retorna 3 se A vencer B, B vencer C e C vencer A; -3 se for exatamente o oposto; e algo entre o contrário. Em detalhe:

  • 1⌽⍵é a rotação única de . Se for ABC, a rotação é BCA.

  • ∘.-calcula uma tabela de subtração entre dois vetores ( 1 2...10 ∘.× 1 2...10seria a tabela de multiplicação que conhecemos da escola). Aplicamos isso entre cada ¨item ( ) e o item correspondente em 1⌽⍵.

  • × sinal de todos os números nas tabelas de subtração

  • ∊¨ achatar cada mesa

  • +/¨e somar. Agora, temos três números que representam saldos: número de vitórias menos casos perdidos para cada um de A vs B, B vs C, C vs A.

  • × signum daqueles

  • +/ soma

Depois, lide com os casos:

  • 3≠|S←T⍵:'none'se T⍵o valor absoluto de não for 3, retorne 'none'

  • N←'nontransitive' vamos precisar muito dessa palavra

  • S=D←T∘.+⍨¨⍵:'strongly ',Ncalcular Tpares de dados ( ∘.+⍨¨⍵← → ⍵((∘.+)¨)⍵) e retornar "fortemente ..." se as mesmas relações entre o ABC ainda se mantiverem

  • S=-D:'Grime-',N Gr "Grime" se os relacionamentos estiverem em direções opostas

  • N se tudo mais falhar, apenas "não-transitivo"

ngn
fonte
1
Você chegou antes de mim! Eu estava trabalhando nesse problema há 3 dias, mas depois parei de escrever minha resposta. É muito parecido com o seu de qualquer maneira, então eu vou postá-lo aqui. É um pouco menor em 100 caracteres:{T←{+/×+/¨∊¨×⍵∘.-¨1⌽⍵}⋄3≠|S←T⍵:'none'⋄N←'nontransitive'⋄S=D←T∘.+⍨¨⍵:'strongly ',N⋄S=-D:'Grime-',N⋄N}
Tobia
@ MartinBüttner: O termo correto no título é "caracteres", porque a quantidade de bytes varia dependendo do conjunto de caracteres usado para codificar os símbolos da APL. Tradicionalmente, eles eram codificados na metade superior dos bytes de 8 bits, após o ASCII. Atualmente, usamos UTF-8, mas os conjuntos de caracteres antigos ainda são úteis ... principalmente para reduzir a contagem de bytes à contagem de caracteres ao jogar golfe!
Tobia
@Tobia No código de golfe, trunfos mais curtos antes, então você ganha! Eu não estou realmente familiarizado com etiqueta de golfe, mas acho que você deve publicá-la como uma resposta separada, pois é substancialmente diferente e você chegou a ela de forma independente.
ngn 16/01
@Tobia Eu prefiro contar em caracteres, também, mas se a codificação clássico está implícito, então bytes = caracteres, talvez por isso realmente não importa muito o que chamamos-lhes ...
NGN
@Tobia Bem, é definitivamente inútil fornecer a contagem de caracteres em um desafio que pontua por bytes. No entanto, ninguém nunca disse que estamos marcando em bytes UTF-8. De fato, o tag wiki diz explicitamente que uma codificação existente diferente pode ser usada para caracteres fora do intervalo ASCII. E o APL possui sua própria página de códigos, para que todo o conjunto de caracteres caiba em um byte. A política do PPCG é usar essa página de códigos para contar a APL - dificilmente é justo punir a APL por ser mais velha que a ASCII.
Martin Ender
13

Python 2, 269

Aqui está uma pequena expressão agradável que avalia uma função. Aceita três listas de números inteiros. Passa em todos os casos de teste.

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"
feersum
fonte
2

J - 311 257 bytes

Atualização (13 de janeiro de 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'
)

Explicação: Usando Gerúndios, simplifique os if.s para @.s.

Versão antiga:

Primeiro tente codificar em J e também jogar golfe.

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

Execute-o usando uma sintaxe semelhante à seguinte (espaços extras para maior clareza):

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

Explicação:

gé definido como um diad tomar duas matrizes que diz se primeiro dado bate segundo dado
hé definido como uma diad tomar duas matrizes que diz se jogando duas vezes e soma, faz primeiros dados vencer segunda
fé uma mônada que leva uma tabela e retorna um string com o resposta correta

Editar: corrigir um erro na condição Grime-não-transitória (substituindo ,por *)

Jay Bosamiya
fonte
Gostaria muito de sugestões para melhorias. :)
Jay Bosamiya
@ MartinBüttner, eu tinha tentado inicialmente isso, mas não sabia como concatenar várias linhas (ou frases, como é conhecido em J) sem aumentar muito o tamanho do código ... aprender mais sobre "gerúndios" me levou a fazer o muitas frases em uma que acaba encurtando o código, bem ...
Jay Bosamiya
1

Pitão 129 133

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

Tente aqui , ou pelo menos você poderia, mas o online evalnão parece gostar de listas de listas :( Se você quiser experimentá-lo, armazene manualmente uma lista de 3 dados em uma variável não usada pelo programa e substitua todas as instâncias Qdessa variável.Um exemplo de inicialização:

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

Isso passa em todos os casos de teste de Martin, não tenho o coração examinado todos os casos de Peter: P

Explicação (isso vai ficar doozy)

Lmsd^b2

Muito simples, cria uma função yque retorna a soma de cada par de valores cartesianos de forma iterável. Para equivalentes: def y(b):return map(lambda d:sum(d),product(b,repeats=2)). Isso é usado para criar matrizes de vários lados que simulam jogar as matrizes regulares duas vezes.

Msmsm>bkGH

Define uma função gde 2 argumentos que retorna quantas vezes um dado vence outro. Equivalente a def g(G,H):return sum(map(lambda k:sum(map(lambda b:b>k,G)),H).

DPNK-ghNeNgeNhNR?^tZ<KZKZ

Define uma função Pque recebe uma lista de dois dados como argumento. Isso retorna -1 se o primeiro dado 'perder', 0 para um empate e 1 se o primeiro dado 'vencer'. Equivalente a:

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

A AGHatribuição atua como uma atribuição python de 2 tuplas. EssencialmenteG,H=(result)

msdCm,PkP,yhkyekm,@Qb@QhbUQ

Indo para trás através dos mapas. m,@Qb@QhbUQitera sobre b = 0..2 e gera 2 tuplas de dados com o índice be índice b + 1. Isso nos dá dados (A, B), (B, C), (C, A) (pyth modifica automaticamente os índices pelo comprimento da lista).

Em seguida, m,PkP,yhkyekitera sobre o resultado do mapa anterior, com cada par de dados sendo armazenado em k em cada execução. Retorna tuple(P(k),P(tuple(y(k[0]),y(k[-1]))))para cada valor. Isso se resume a `((A bate B ?, 2 * A bate 2 * B), (B bate C ?, 2 * B bate ..)).

Finalmente, msdCsoma os valores do mapa anterior depois que ele foi compactado. O zíper faz com que todos os dados individuais 'batam' na primeira tupla e os dados duplos na segunda.

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

Uma coisa nojenta que imprime os resultados. Se L é 0 ou não divisível por três, este capturas bot +/- 3, ( |!G%G3), gravuras none, de outra forma imprime a soma da lista follwing: [not(G+H)*"Grime",(G==H)*"strongly ","nontransitive"]. Eu acho que os booleanos são bastante auto-explicativos no que diz respeito às definições na pergunta. Observe que G não pode ser zero aqui, pois isso é capturado pela verificação anterior.

FryAmTheEggman
fonte
1

J (204)

Por muito tempo, provavelmente poderia ser muito jogado por ter um sistema mais eficiente para escolher a corda certa.

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.
)
ɐɔıʇǝɥʇuʎs
fonte
1

Matlab (427)

Não é tão curto e tenho certeza de que pode jogar muito mais, tentei resolver esse desafio porque achei que era uma tarefa muito divertida, então obrigado a MartinBüttner por criar esse desafio!

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

Aqui está o código completo com alguns comentários, se você quiser entender o que está acontecendo. Incluí alguns casos de teste hare e excluí os comandos de entrada:

%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);
flawr
fonte
Não é mais curto se você ler uma matriz input()e depois atribuir os três elementos a,b,c? Além disso, por favor use as cordas exatas nas especificações ( none, nontransitivee capitalizado Grime) ... deve provavelmente até poupar bytes.
Martin Ender
Sim, isso provavelmente seria mais curto, vou dar uma olhada nisso. As strings serão exatamente aquelas que acabei de remover os dispcomandos na versão longa, elas eram apenas para testar o programa, mas a mensagem final é armazenada m. E eu corrigi o G.
flawr
0

JavaScript - 276 bytes

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')}

Não sou muito bom em probabilidade; portanto, para ter certeza dos meus resultados, prefiro jogar os dados centenas de milhares de vezes.

A expressão é avaliada como uma função, que deve ser chamada com apenas um argumento: uma matriz de três matrizes de números inteiros. Verifique o Fiddle para poder executar o código sozinho.

Aqui está a versão não destruída:

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);
}
Blackhole
fonte
Hum, não acho que isso esteja realmente no espírito do desafio. Você basicamente transformou isso de um desafio da teoria das probabilidades em um desafio estatístico. ;) ... Em vez de jogadas aleatórias, você pode simplesmente enumerar todas as jogadas possíveis exatamente uma vez. Isso daria os resultados exatos (e seria muito mais rápido).
Martin Ender
Vou verificar se isso leva a um script mais conciso. Obrigado pelo teu conselho :).
Blackhole