Maior soma divisível por n

16

Eu fiz essa pergunta no StackOverflow , mas acho que aqui é um lugar mais apropriado.

Este é um problema do curso Introdução aos algoritmos :

Você tem uma matriz a com números inteiros positivos (a matriz não precisa ser classificada ou os elementos exclusivos). Sugira um algoritmo para encontrar a maior soma de elementos divisível por .nnO(n)n

Exemplo: . A resposta é (com elementos )56a=[6,1,13,4,9,8,25],n=7566,13,4,8,25

É relativamente fácil encontrá-lo em usando programação dinâmica e armazenando a maior soma com o restante .0 , 1O(n2)0,1,2,...,n1

Além disso, se restringirmos a atenção a uma sequência contígua de elementos, é fácil encontrar a sequência ideal em tempo, armazenando somas parciais no módulo : deixe , para cada restante lembre-se do maior índice modo que S [j] \ equiv r \ pmod {n} e, em seguida, para cada i considere S [j] -S [i] onde j é o índice correspondente a r = S [i] \ bmod n .n S [ i ] = a [ 0 ] + a [ 1 ] + + a [ i ]O(n)nS[i]=a[0]+a[1]++a[i]j S [ j ] rrji S [ j ] - S [ i ] j r = S [ i ] mod nS[j]r(modn)iS[j]S[i]jr=S[i]modn

Mas existe uma solução de tempo O(n) para o caso geral? Todas as sugestões serão apreciadas! Considero que isso tem algo a ver com álgebra linear, mas não sei exatamente o que.

Como alternativa, isso pode ser feito no tempo O(nlogn) ?

delta-terminator
fonte
2
1. Você postou exatamente a mesma pergunta no Stack Overflow. Por favor, não postar a mesma pergunta em vários sites . Não queremos várias cópias flutuando em vários sites SE. Se você não obteve uma resposta aceitável, não há problema em sinalizar sua pergunta para migração para outro site, mas não repassar a mesma coisa em outro lugar. 2. Você pode dar uma referência / citação / link para o livro ou curso onde ele apareceu? Você tem certeza de que existe uma solução de tempo ? O(n)
DW
5
O desafio da sua universidade ainda está aberto? Seria realmente útil ver o link para o curso, a pergunta exata e se for realmente e as pessoas que o prepararam explicarão / publicarão sua resposta, seria incrível. O(n)
Mal
É relativamente fácil encontrá-lo em O (n2) O (n2) usando programação dinâmica e armazenando a maior soma com o restante 0,1,2, ..., n-10,1,2, ..., n-1. Você poderia elaborar um pouco isso? Eu posso entender como isso seria n-quadrado se considerarmos apenas elementos contíguos, mas também com elementos não contíguos, não seria exponencial em ordem?
Nithish Inpursuit Ofhappiness

Respostas:

4

Aqui estão algumas idéias aleatórias:

  • O algoritmo de programação dinâmica pode ser invertido para procurar uma menor soma em vez de uma maior soma. Você acaba procurando uma soma congruente com o restante da soma de toda a matriz, em vez de uma congruente com zero. Se processarmos os elementos em ordem crescente, isso às vezes permitirá que o algoritmo dinâmico termine antes de processar toda a matriz.

    O custo seria se processarmos elementos. Há não um limite inferior de sobre este algoritmo porque não temos para ordenar todos os elementos. Leva apenas tempo para obter os menores elementos.k Ω ( n log n ) O ( nO(nk)kΩ(nlogn)O(nlogk)k

  • Se nos importamos com o conjunto com o tamanho maior, em vez do conjunto com a maior soma, poderemos usar a multiplicação polinomial baseada na transformação de Fourier mais rápida para resolver o problema em hora. Semelhante ao que é feito no 3SUM quando o domínio é limitado. (Nota: use o quadrado repetido para fazer uma pesquisa binária, caso contrário, você obterá onde é o número de elementos omitidos.)O ( n k ( log n ) ( log logO(n(logn)2(loglogn))O(nk(logn)(loglogn))k

  • Quando é composto e quase todos os restantes são múltiplos de um dos fatores de , um tempo significativo pode ser economizado, concentrando-se nos restantes que não são múltiplos desse fator.nnn

  • Quando um restante ré muito comum, ou há apenas alguns restantes, acompanhar as informações do 'próximo espaço aberto se você começar daqui e continuar avançando r' pode salvar muitas informações de varredura para saltos em locais abertos Tempo.

  • Você pode raspar um fator de log rastreando apenas a acessibilidade e usando máscaras de bits (no algoritmo dinâmico invertido) e, em seguida, recuando quando atingir o restante do destino.

  • O algoritmo de programação dinâmica é muito passível de ser executado em paralelo. Com um processador para cada slot de buffer, você pode descer para . Como alternativa, usando largura e divida e conquiste agregação em vez de agregação iterativa, o custo da profundidade do circuito pode chegar até .O(n)O(n2)O(log2n)

  • (Meta) Suspeito veementemente que o problema que você deu seja sobre somas contíguas . Se você se vinculou ao problema real, seria fácil verificar isso. Caso contrário, estou muito surpreso com a dificuldade desse problema, uma vez que ele foi designado em um curso chamado "Introdução aos algoritmos". Mas talvez você tenha ensinado um truque em sala de aula que o torna trivial.

Craig Gidney
fonte
Para o ponto um. Não está escrito nas especificações do problema, então você não pode assumir isso. Além disso, o problema não é dizer que você não pode modificar a matriz ou criar novas, de fato. A única coisa que você precisa fazer é encontrar os números que somados fornecem a maior soma divisível por na complexidade de tempo de O ( n ) (geralmente é assumida apenas a complexidade de tempo). nO(n)
Nbro 08/03
2
@EvilJS O subconjunto com a maior soma com o restante 0 é igual ao conjunto completo depois de remover o subconjunto com a menor soma com o restante congruente com a soma do conjunto completo. Procurar uma menor soma congruente para é mais conveniente do que procurar uma maior soma congruente para r 2, pois permite que você termine assim que encontrar uma solução (ao processar elementos em ordem crescente) em vez de precisar continuar. r1r2
Craig Gidney
-1

Meu algoritmo proposto é o seguinte:

Uma soma é divisível por n se você adicionar apenas ordens que são múltiplos de n.

Antes de começar, crie um hashmap com uma int como chave e uma lista de índices como valor. Você também cria uma lista de resultados contendo índices.

Em seguida, você faz um loop na matriz e adiciona todos os índices cujo mod n é zero à sua lista de resultados. Para todos os outros índices, faça o seguinte:

Você subtrai o valor mod n deste índice de n. Este resultado é a chave do seu hashmap que armazena índices para elementos com o valor necessário. Agora, você adiciona esse índice à lista no mapa de hash e segue em frente.

Depois de terminar o loop sobre a matriz, você calcula a saída. Você faz isso classificando cada lista no mapa de hash de acordo com o valor que o índice aponta. Agora você considera cada par no hashmap totalizando n. Portanto, se n = 7, você pesquisará no hashmap 3 e 4. Se tiver uma entrada nos dois, você pega os dois maiores valores, remove-os de suas listas e os adiciona à sua lista de resultados.

Última recomendação: ainda não testou o algoritmo, escreva um caso de teste usando um algoritmo de força bruta.

Tobias Würfl
fonte
2
Ganancioso, linear, não está funcionando. Você considera apenas os elementos divisíveis por n e os pares divisíveis por n, e os triplos e mais? Não garante a soma máxima de subconjuntos em maiúsculas e minúsculas. [2, 1, 8] -> soma máxima é 9, mas seu algoritmo retorna 3.
Mal
@EvilJS o que aconteceu com o seu algoritmo sub- ? n2
Delta-terminator
Obrigado por apontar esse erro para mim. Minha idéia sobre melhoria seria criar um mapa de hash de pilhas de listas, ordenadas por valor crescente e começar a acumular-se apenas após a conclusão de uma passagem pela matriz.
Tobias Würfl
Você quer dizer matriz de matrizes, que serão classificadas, e "mapa de hash" é% n? Você ainda precisa classificá-los e, se você os classificou, aceitar o valor mínimo / máximo é aceitável, mas ainda existe uma parte inevitável da escolha real do subconjunto, o que, na pior das hipóteses, não beneficia. Enfim, se você tiver algumas melhorias, talvez você possa editar a postagem?
Mal
Sim, foi uma ideia bastante rápida com as pilhas. Na verdade, você só precisa de listas no hashmap que você classifica. Eu não tinha certeza se é educado editar minha primeira resposta. Afinal, cometi um erro na minha primeira tentativa.
Tobias Würfl 10/03
-2

use esse método DP de ( /programming/4487438/maximum-sum-of-non-consecutive-elements?rq=1 ):

Dada uma matriz A [0..n], seja M (i) a solução ideal usando os elementos com índices 0..i. Então M (-1) = 0 (usado na recorrência), M (0) = A [0] e M (i) = máx (M (i - 1), M (i - 2) + A [i ]) para i = 1, ..., n. M (n) é a solução que queremos. Este é O (n) . Você pode usar outra matriz para armazenar a escolha feita para cada subproblema e, assim, recuperar os elementos reais escolhidos.

Altere a recursão para M (i) = max (M (i - 1), M (i - 2) + A [i]) de modo que seja armazenado apenas se for divisível por N

Pinhead
fonte
2
Isso não funciona - eu vou deixar você descobrir o porquê. (Dica: tente executá-lo na matriz constante 1.) Além disso, neste problema, permitimos elementos consecutivos.
Yuval Filmus
1
Esta é uma solução muito boa, apenas para um problema totalmente diferente (e muito mais fácil).
Mal