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 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 .n
Exemplo: . A resposta é (com elementos )56
É relativamente fácil encontrá-lo em usando programação dinâmica e armazenando a maior soma com o restante .0 , 1
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 ]j S [ j ] ≡ ri S [ j ] - S [ i ] j r = S [ i ] mod n
Mas existe uma solução de tempo 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 ?
fonte
Respostas:
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.nn n
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çandor
' 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.
fonte
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.
fonte
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
fonte