Encontre o diâmetro de um gráfico de palavras

12

Introdução

Um quebra-cabeça popular é converter uma palavra em outra através de uma série de etapas que substituem apenas uma letra e que sempre resultam em uma palavra válida. Por exemplo, o BAG pode ser convertido em DOG por um caminho de cinco etapas:

SACO -> BAT -> CAT -> BOLO -> COG -> CÃO

Caminhos mais curtos também existem neste caso; por exemplo:

SACO -> BOG -> CÃO

Se alguém desenhasse um gráfico cujos vértices fossem rotulados por palavras, com uma aresta entre qualquer par de palavras que diferisse em uma letra, o caminho mais curto de "BAG" a "CÃO" consistiria em duas arestas.

Desafio

Você deve escrever um programa que receba como entrada um "dicionário" de palavras com o mesmo comprimento, representando todas as palavras permitidas que podem aparecer como etapas ao longo de um caminho. Ele deve gerar pelo menos um "caminho mais curto e mais longo", ou seja, um caminho entre duas das palavras que é:

  • não mais do que qualquer outro caminho entre essas duas palavras;

  • pelo menos enquanto o caminho mais curto possível entre qualquer outro par de palavras da lista.

No contexto do gráfico descrito acima, o comprimento desse caminho é o diâmetro do gráfico.

No caso degenerado em que nenhuma das palavras de entrada pode ser transformada em nenhuma das outras, imprima pelo menos um caminho de comprimento zero, ou seja, uma única palavra.

Exemplos

  • A entrada ["saco", "bastão", "gato", "berço", "ponto", "cachorro"] deve gerar um caminho que percorra todas as seis palavras nessa ordem (ou ordem reversa), já que o caminho mais curto de " saco "para" cachorro "dentro deste dicionário é o mais longo possível, cinco etapas.

  • A entrada ["bolsa", "bastão", "bot", "gato", "berço", "ponto", "cachorro"] deve gerar o caminho "bolsa, bastão, bot, ponto, cachorro" e / ou sua reversão.

  • A entrada ["code", "golf", "male", "buzz", "mole", "role", "mould", "cold", "gold", "mode"] deve gerar um caminho entre "code" e "golfe".

  • A entrada ["um", "dois", "seis", "dez"] corresponde a um gráfico sem arestas; portanto, imprima um ou mais caminhos de palavra única (comprimento zero).

  • Se a entrada contiver duas palavras com comprimento desigual, a saída será indefinida.

Regras

  • Aplicam-se as regras de código padrão do golfe
  • Haverá vários caminhos "mais curtos". Você deve produzir pelo menos um, mas pode liberar quantos quiser.
  • Você é livre para decidir como o dicionário de entrada é passado para o seu programa.
  • O código mais curto em bytes vence.
jnfnt
fonte
3
Importa-se de adicionar mais alguns casos de teste?
Jonah
Feito. Também foi adicionada uma discussão do caso em que o gráfico não contém arestas.
jnfnt
Devemos aceitar uma entrada vazia (a resposta seria []ou [[]])?
Erik the Outgolfer
Estou feliz por o comportamento ser indefinido em entradas vazias.
jnfnt

Respostas:

3

APL (Dyalog Classic) , 84 80 77 76 74 66 61 bytes

{⍵⌷⍨{⍵,⍨⊃⍋(1a⌷⍨⊃⍵),⍪⍺⌷a}⍣d/⊃⍸a=d←⌈/512|,a←⌊.+⍨⍣≡9*⍨2⌊⍵+.≠⍉⍵}

Experimente online!

entrada e saída são matrizes de caracteres

⍵+.≠⍉⍵ matriz de distâncias hamming-like entre palavras

9*⍨2⌊deixe 0s e 1s intactos, transforme 2+ em um número grande (512 = 2 9 , usado como "∞")

⌊.+⍨⍣≡ algoritmo de caminho mais curto da floyd & warshall

  • ⌊.+como multiplicação de matrizes, mas usando min( ) e em +vez de +e ×respectivamente

  • use a mesma matriz à esquerda e à direita

  • ⍣≡ repita até a convergência

d←⌈/512|, comprimento do caminho mais longo (não "∞"), atribuído a d

⊃⍸a=que dois nós é que conectar, vamos chamá-los i e j

{⍵,⍨⊃⍋(1≠a⌷⍨⊃⍵),⍪⍺⌷a}⍣d/ reconstruir o caminho

  • { }⍣d/avaliar os tempos de { }função d. o argumento esquerdo é sempre i . o argumento certo inicia como je acumula gradualmente os nós internos do caminho

  • (1≠a⌷⍨⊃⍵),⍪⍺⌷a construa uma matriz de duas colunas desses dois vetores:

    • 1≠a⌷⍨⊃⍵ booleanos (0 ou 1) indicando quais nós estão na distância 1 ao primeiro

    • ⍺⌷a distâncias de todos os nós do gráfico para

  • ⊃⍋ índice da linha lexicograficamente menor

  • ⍵,⍨ anexar a

⍵⌷⍨ indexe as palavras originais com o caminho

ngn
fonte
2

Python 3 , 225 bytes

from itertools import*
def f(a):b=[((p[0],p[-1]),(len(p),p))for i in range(len(a))for p in permutations(a,i+1)if all(sum(q!=r for q,r in zip(*x))<2for x in zip(p,p[1:]))];return max(min(r for q,r in b if x==q)for x,y in b)[1]

Experimente online!

Basicamente, siga todos os caminhos possíveis, mantenha apenas os que são válidos e, em seguida, passe por cada combinação de início e fim, encontre a distância mínima do caminho e o máximo disso.

HyperNeutrino
fonte
1

JavaScript (ES6),  195  194 bytes

Retorna [optimal_length, [optimal_path]].

f=(a,p=[],w=o=[],l=0)=>Object.values(o,o[k=[w,p[0]]]=(o[k]||0)[0]<l?o[k]:[l,p],a.map((v,i)=>w+w&&[...v].map((c,i)=>s-=c!=w[i],s=1)|s||f(a.filter(_=>i--),[...p,v],v,l+1))).sort(([a],[b])=>b-a)[0]

Experimente online!

Quão?

fow0w1[l,p]pw0w1l

plwpo

o[k = [w, p[0]]] = (o[k] || 0)[0] < l ? o[k] : [l, p]

o

Object.values(o).sort(([a], [b]) => b - a)[0]

(esse código é executado a cada profundidade de recursão, mas apenas o nível raiz realmente importa)

vw

[...v].map((c, i) => s -= c != w[i], s = 1) | s

v

f(                    //
  a.filter(_ => i--), // remove the i-th word from a[]
  [...p, v],          // append v to p[]
  v,                  // pass v as the last word
  l + 1               // increment the length of the path
)                     //
Arnauld
fonte
0

Python 3, 228 bytes.

def G(w):
    D={A+B:[A,B]if sum(a!=b for a,b in zip(A,B))<2else[0,0]*len(w)for A in w for B in w}
    for k in w:
        for i in w:
            for j in w:
                p=D[i+k]+D[k+j][1:]
                if len(p)<len(D[i+j]):D[i+j]=p
    return max(D.values(),key=len)

Implementa o algoritmo Floyd-Warshall para os caminhos mais curtos de todos os pares e, em seguida, assume o máximo sobre os caminhos encontrados.

16 dos caracteres nesta implementação são guias, o que é lamentável :(

rikhavshah
fonte
2
Isso parece quebrar quando existe um vértice sem arestas de incidente, por exemplo, "print G (['bag', 'bat', 'berço'])"
jnfnt 20/06/19
Golfe ponta para Python recuo: usar um espaço para o primeiro nível, uma guia para a segunda, um separador e um espaço para o terceiro, duas guias para o quarto, etc.
Peter Taylor
1
@ Petereteray Boa dica, mas funciona apenas para o Python 2. O Python 3 não permite misturar guias com espaços.
OOBalance
1
Ah, boa captura @jnfnt. Agora que penso nisso, ele só funciona quando o gráfico está conectado.
Rikhavshah