AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 77810560
Accepted
ABGR
ABGR
Asked: 2024-01-13 14:50:02 +0800 CST2024-01-13 14:50:02 +0800 CST 2024-01-13 14:50:02 +0800 CST

Alcançando o vértice d em um tetraedro em n etapas

  • 772

Eu estava resolvendo este problema:

Dado um tetraedro com vértices A, B, C e D. Uma formiga está no vértice D. A formiga não fica parada. Ele continuará se movendo de um vértice para outro ao longo de alguma aresta do tetraedro. Sua tarefa é contar o número de maneiras pelas quais a formiga pode ir do vértice inicial D até si mesma em exatamente n passos.

Então, para entrada 2 Saída: 3

Consegui resolver isso confortavelmente usando recursão da seguinte maneira. Mas não parece muito eficiente para uma entrada grande, digamos, 15, devido à sua complexidade de tempo.

Isso pode ser resolvido através de programação dinâmica, mas não vejo nenhum escopo de memoização na minha abordagem atual. Talvez eu precise mudar a abordagem. Então aprecio qualquer ajuda.

Eu gostaria de resolver isso usando recursão + memoização

var count = 0;
function recursion(n, arr=['d']){
    if(n <=1) return 0;
  
  if(arr.length === n+1 && arr[arr.length-1] ==='d'){
    console.log(arr.join(" -> "))
    count++;
    return;
  }

  if(arr.length > n+1) return;

  for(let el of ['a', 'b', 'c', 'd']){
    if(arr[arr.length-1] != el){
       recursion(n, [...arr, el]);
    }
  }
}
recursion(3)

console.log(count);

algorithm
  • 1 1 respostas
  • 54 Views

1 respostas

  • Voted
  1. Best Answer
    trincot
    2024-01-13T17:44:39+08:002024-01-13T17:44:39+08:00

    Você realmente pode usar memoização aqui.

    Primeiro vamos analisar as relações de recorrência.

    Definir:

    • 𝑆 𝑛 como o número de caminhos de comprimento 𝑛 para ir de um vértice até ele mesmo.

    • 𝐷 𝑛 como o número de caminhos de comprimento 𝑛 para ir de um vértice a outro escolhido . Não importa qual vértice de destino escolhemos, pois o tetraedro é completamente simétrico.

    Agora as relações de recorrência:

    Para obter o número de caminhos de comprimento 𝑛 até o vértice original (𝑆 𝑛 ), você pode escolher um vizinho entre três vizinhos e depois contar o número de caminhos (mais curtos) de lá até o vértice inicial, que é dado por 𝐷. Então:

          𝑆 𝑛 = 3𝐷 𝑛−1

    Para obter o número de caminhos de comprimento 𝑛 para um vértice diferente (𝐷 𝑛 ), você pode escolher esse vizinho e contar o número de caminhos (1 passo mais curto) dele até ele mesmo, ou pode escolher um dos outros dois vizinhos e conte o número de caminhos (1 passo mais curto) de lá até o vértice de destino. Então:

          𝐷 𝑛 = 𝑆 𝑛−1 + 2𝐷 𝑛−1

    A última equação pode ser expandida por substituição a esta relação de recorrência:

          𝐷 𝑛 = 3𝐷 𝑛−2 + 2𝐷 𝑛−1

    Ao referenciarmos 𝑛−2, precisamos ter pelo menos dois casos base:

    • 𝐷 0 = 0 (não existem caminhos de tamanho 0 que levem você a outro vértice)
    • 𝐷 1 = 1 (há um caminho de tamanho 1 de um vértice para outro)

    Implementação

    Como temos uma boa relação de recorrência para 𝐷, poderíamos primeiro implementar uma função que devolve o número de caminhos de um vértice para outro . E então use a primeira relação para traduzir a consulta original (para o número de caminhos para o mesmo vértice) nesse problema:

    // Memoize the number of paths from one vertex to a different one
    const memo = new Map().set(0, 0).set(1, 1);
    
    function numPathsToOther(size) {
        let result = memo.get(size);
        if (result === undefined) {
            result = 3*numPathsToOther(size-2) + 2*numPathsToOther(size-1);
            memo.set(size, result);
        }
        return result;
    }
    
    function numPathsToSelf(size) {
        return size ? 3 * numPathsToOther(size - 1) : 1;
    }
    
    // Demo runs for the first few path-sizes:
    for (let i = 0; i <= 10; i++) {
        console.log(i, numPathsToSelf(i));
         console.log((3*0^i-(-4)^i)/4)
    }

    Exemplo

    Digamos que rotulamos os quatro vértices como 𝑎, 𝑏, 𝑐 e 𝑑 como você fez, e que 𝑛 é 3. Queremos saber o número de caminhos de tamanho 𝑛 que começam e terminam no vértice 𝑎.

    Existem três maneiras de iniciar esse caminho: 𝑎→𝑏, 𝑎→𝑐 ou 𝑎→𝑑. Vamos pegar 𝑎→𝑏. Agora precisamos saber quantos caminhos existem de tamanho 2 que começam em 𝑏 e terminam em 𝑎.

    Aqui, vamos parar por um minuto. Você pode perceber que não há nada de especial em 𝑎 e 𝑏. Eles são apenas vizinhos, mas aí vem: quaisquer dois vértices em um tetraedro são vizinhos e se relacionam entre si da mesma maneira que 𝑎 a 𝑏. Portanto, podemos generalizar este caso como “o número de caminhos de um vértice a outro” !

    Para o caso em que o tamanho desse caminho precisa ser 2, existem apenas dois caminhos possíveis de 𝑏 que terminam em 𝑎: ou passamos por 𝑐 ou passamos por 𝑑.

    Agora voltamos à situação inicial. Dissemos que caminhos de tamanho 3 de 𝑎 de volta a 𝑎 poderiam passar primeiro por 𝑏, e agora sabemos que de 𝑏 existem duas possibilidades. Mas também poderíamos ter passado de 𝑎 para 𝑐, ou de 𝑎 para 𝑑. E como o tetraedro é completamente simétrico, podemos concluir imediatamente que também essas duas alternativas representam 2 caminhos cada. Portanto, no total encontramos 3x2=6 caminhos.

    Esta pequena análise mostra que é útil saber qual é o número de caminhos de um vértice a outro vértice.

    Fórmula fechada

    A relação de recorrência tem solução. oeis.org fornece:

    Número de passeios fechados de comprimento n ao longo das arestas de um tetraedro baseado em um vértice.

    FÓRMULA a(n) = (3^n + (-1)^n*3)/4.

    for (let i = 0; i <= 10; i++) {
        console.log(i, (3**i + (-1)**i*3)/4)
    }

    • 1

relate perguntas

  • Encontre o menor número inteiro positivo, que não divide nenhuma diferença mútua de inteiros em uma matriz

  • O último dígito de um grande número de casos de teste falha em Golang Codewars

  • Escreva um programa LMC que calcule a soma dos números inseridos pelo usuário. Exibir soma antes de parar

  • Como determinar os estados alcançáveis ​​no problema de 3 jarras de água?

  • Encontre o número de pares de números naturais de l a r que bit a bit AND é igual a 0

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle?

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Quando devo usar um std::inplace_vector em vez de um std::vector?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Martin Hope
    Aleksandr Dubinsky Por que a correspondência de padrões com o switch no InetAddress falha com 'não cobre todos os valores de entrada possíveis'? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer Quando devo usar um std::inplace_vector em vez de um std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB Por que o GCC gera código que executa condicionalmente uma implementação SIMD? 2024-02-17 06:17:14 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve