Blue Bridge Cup Joseph Ring (recursão)

1. Descrição do problema:

O número de n indivíduos é 1 ~ n, se eles estiverem dispostos em um círculo no sentido horário de acordo com o número, o número é relatado no sentido horário pela pessoa com o número 1. (O número é relatado de 1) Quando o número é relatado para k, a pessoa se retirará do círculo de jogo. A próxima pessoa começa a contar a partir de 1 novamente. Encontre o número da última pessoa restante. Este é o famoso problema do anel de Joseph. Esta questão é encontrar o número da última pessoa remanescente quando n e k são conhecidos.

Digite a descrição

A entrada é uma linha com dois inteiros separados por espaços n, k (0 <n, k <10 ^ 7)

Descrição de saída

É necessário produzir um número inteiro que representa o número da última pessoa restante.

Entrada e saída de amostra

Entrada: 10 3

Produto: 4

Limite
operacional Tempo máximo de operação: 1s
Memória operacional máxima: 256M

2. Análise de pensamento:

① A maneira mais fácil de pensar no início é o método de simulação. A programação simula todo o processo para resolvê-lo. Enquanto houver mais de 2 pessoas, o loop é executado. Uma variável é usada no loop para contar e simular o processo de relatar o número. No entanto, como a quantidade de dados é relativamente grande, quando a quantidade de dados é grande, o tempo limite é atingido, portanto não pode ser resolvido por simulação. Na verdade, o anel de Joseph é um problema matemático clássico. A descrição original é: N indivíduos são numerados 1, 2, ..., N e os números são relatados sucessivamente. Toda vez que você relatar a M, mate essa pessoa e peça o número do vencedor final. O problema do anel de Joseph pode ser resolvido por derivação matemática. A resposta é finalmente obtida a partir da derivação da fórmula passo a passo. Pesquisei informações na Internet e descobri que pode ser resolvido depois de entender a ideia. Um exemplo simples será mais fácil de entender. (Usando um exemplo de um cara grande no blog da csdn)

② Exemplo: Há um total de 11 pessoas com números 1, 2, 3 ... 11. Eles formam uma linha primeiro. Supondo que cada pessoa que reporta a 3 é morta, pergunte o número da pessoa que não foi morta no final quantos? A maneira mais fácil é listar primeiro uma tabela que muda dinamicamente para obter o número do vencedor. A seguir está uma tabela do processo de derivação e, em seguida, observar a relação entre o número do vencedor em cada etapa e a etapa anterior.

Supondo que haja uma função f (n, k), a função significa que há atualmente n pessoas relatando o número e o número do vencedor ao relatar para k. De acordo com a fórmula acima, esta fórmula pode ser derivada: f (t , k) = (f (t-1, k) + k)% t, onde t é o número de indivíduos reportados por t atualmente. Em primeiro lugar, comece a partir do primeiro relatório, numerado de 1 a 11. Quando o número 3 é chamado, a pessoa de número 3 é morta, e então a pessoa de número 4 começa a relatar o número de 1 .... Sim. Verifica-se que a pessoa após o número 4 avançou 3 posições ao reportar o número pela segunda vez (o número 4 é classificado em primeiro), e o mesmo é verdade para o último exemplo, até o vencedor final. Então, quando há apenas uma pessoa, então o número do vencedor é 1 (correspondendo ao subscrito 0) para que possamos começar pela pessoa cujo subscrito final é 0 e ir um passo à frente, e podemos encontrar que f (2 , 3) = (f (1, 3) + 3)% 2 (Atualmente, há duas pessoas), que na verdade é o processo inverso agora. Para derivar para a frente (o número do vencedor no início), você precisa mova k posições para trás, então você precisa adicionar 3 (deduz-se para subtrair 3 quando há apenas um vencedor), e atualmente há k pessoas, então meu subscrito não pode exceder k, então preciso pegar o resto de k para indique que o vencedor move k passos para trás Então o subscrito sob o número atual de pessoas, ... até que haja n pessoas, então acabou. Portanto, apenas deduza passo a passo o loop.

De modo geral, é uma questão de se mover para frente ou para trás, o que pode ser entendido observando-se a lei de movimento numérica acima.

3. O código é o seguinte:

if __name__ == '__main__':
    # 本质上是移动了k个位置, 所以我们可以从最后胜利的那个人的下标0开始往上推导
    n, k = map(int, input().split())
    index = 0
    for i in range(2, n + 1):
        # 对i取余是上一步的情况下往后移动k个位置在目前i个人的真实编号
        index = (index + k) % i
    # 因为编号是从1开始的所以要返回index + 1
    print(index + 1)

 

Acho que você gosta

Origin blog.csdn.net/qq_39445165/article/details/115199150
Recomendado
Clasificación