Tela de bloqueio do Android


25

Introdução

Você está sentado em uma sala de diretoria no final de uma longa mesa. Você olha em volta e vê Tim Cook, o Conselho de Administração da Apple, o fantasma de Steve Jobs e Jack Donaghy. A Apple convocou essa reunião porque percebeu o quanto a tela de bloqueio do Android é mais fria e deseja aumentá-la. Todos na sala olham para você enquanto Steve Ghost grita: "Me ajude, CodeGolf Man! Você é minha única esperança!"

O problema

A tela de bloqueio do Android é uma grade de pontos 3 x 3 que pode ser conectada passando um dedo de um ponto para o outro, criando um caminho. Uma senha é considerada qualquer caminho possível que inclua qualquer número de pontos e exclua qualquer número de pontos. (Em um telefone real, o caminho deve ter pelo menos 4 pontos. Para esse desafio, ignore essa restrição.) A Apple planeja substituir a grade 3 x 3 por uma grade M x N, que é (M * N) / 9 vezes melhor!

Regras:

  • Um caminho de ponto zero não é uma senha, mas um caminho de 1 ponto é
  • Um caminho pode cruzar-se
  • Um caminho não pode cruzar diretamente sobre um ponto sem incluir esse ponto
  • Um ponto só pode ser usado uma vez
  • Caminhos idênticos por rotação não são a mesma senha
  • Caminhos idênticos, mas ordenados ao contrário, não têm a mesma senha
  • Por exemplo, em uma grade 3x3 com pontos numerados de 1 a 9:

    1 2 3
    4 5 6
    7 8 9
    

    Alguns caminhos válidos são:

    1
    3
    7,2,3
    1,5,9,2
    1,8,6,5,4
    4,2,3,5,6,7,8,9
    5,9,6,4
    

    E alguns caminhos inválidos são:

    1,3
    1,9,5
    7,5,4,7
    4,6
    

    Sua entrada será de três números:

    (M,N,d)
    

    Onde a grade é M x N e d é o comprimento do caminho

    1 <= M <= 16
    1 <= N <= 16
    1 <= d <= M * N
    

    Seu programa ou função receberá a entrada como uma sequência separada por vírgula e deve retornar o número de senhas possíveis desse comprimento. Por exemplo:

    Input:  2,2,1 
    Output: 4
    Input:  2,2,2
    Output: 12
    Input:  7,4,1
    Output: 28
    

    Aplicam-se as regras de código padrão do golfe, o código mais curto vence!

    //If I've made a mistake or the rules are unclear, please correct me!
    

    2
    A entrada é uma sequência separada por vírgula ou três parâmetros separados?
    user80551

    1
    @ user80551 Com base no contexto, creio que será uma cadeia de caracteres se for inserida em um programa ou parâmetros separados se for usada para chamar a função.
    user12205

    1
    @Platatat você pode agradar a pergunta de resposta do user80551, pois isso é muito importante para projetar o código
    RononDex

    3
    Você deve decidir se haverá um limite de tempo para o tempo de compilação e execução de uma determinada solução. Sem esse limite, é fácil escrever um programa que, em teoria, verifique quais de todas as 256!permutações dos pontos na grade 16 x 16 representam um padrão de desbloqueio válido. Na prática, esse programa nunca terminaria.
    Dennis

    3
    Mas eu disse que o problema era baseado no sistema de bloqueio do Android ... Então, por que não devo usar as mesmas regras do sistema de bloqueio do Android?
    Platatat 03/04

    Respostas:


    14

    Python - 170 bytes

    from fractions import*
    p=lambda m,n,d,l=0,s=set():d<1or sum([p(m,n,d-1,i,s|{i})for i in range(m*n)if not(s and(s&{i}or set(range(l,i,abs(i-l)/gcd(i%n-l%n,i/n-l/n)))-s))])
    

    Percebo que os suportes internos sum([...])não são estritamente necessários, mas há uma grande penalidade de desempenho por não incluí-los.

    Saída para todos os 3x3s:

    for i in range(4, 10):
      print p(3, 3, i)
    

    Produz:

    1624
    7152
    26016
    72912
    140704
    140704
    

    Para fins de teste / confirmação, os 6 primeiros valores de uma placa 4x5:

    20
    262
    3280
    39644
    459764
    5101232
    

    4x5 é um caso interessante a ser verificado, pois possui saltos de peg 2x2, 3x3 e 2x4.


    Breve explicação

    Em geral, esta é uma pesquisa exaustiva, com poda cumulativa. Por exemplo, por p(3, 3, 4)ser 1624, p(3, 3, 5)verificará apenas 8120 possibilidades, em vez de verificar ingenuamente todos os 15120. A maior parte da lógica está contida na condição:

    if not(s and(s&{i}or set(range(l,i,abs(i-l)/gcd(i%n-l%n,i/n-l/n)))-s))
    

    Em inglês simples, isso pode ser entendido como:

    If no pegs have been used yet
         OR
       the target peg has not yet been used
         AND
       each of the pegs directly between the target peg and the
       current peg (a.k.a. "jumped over") have already been used
    

    2
    Você poderia explicar o que está acontecendo aqui?
    ɐɔıʇǝɥʇuʎs

    1
    Você pode salvar alguns bytes por ter sum conjunto em vez de uma lista. Não estou vendo a grande penalidade de desempenho ao soltar os colchetes; por que haveria tal penalidade?
    User2357112 suporta Monica

    1
    @ user2357112 um está somando em um gerador e o outro em uma lista. Com o CPython, você está certo, não há muita diferença (apenas cerca de 20% mais lenta). Com o PyPy, é 5 vezes mais lento.
    Primo1

    1
    @ user2357112 Finalmente entendi o que você quis dizer com definir scomo conjunto. Minha lição de python para hoje: {i}avalia como set([i]). Eu esperava um erro de sintaxe. A adição de um item a um conjunto torna-se s|{i}e também permite i in sser substituída por s&{i}.
    Primo
    Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
    Licensed under cc by-sa 3.0 with attribution required.