Um sistema que estou construindo inclui um conjunto de controles deslizantes da interface do usuário (o número varia), cada um com uma escala de 0 a 100. Por slider, quero dizer uma interface do usuário onde você pega um elemento e o arrasta para cima e para baixo, como um controle de volume. Eles são conectados por um algoritmo que garante que sempre totalizem 100. Portanto, quando um controle deslizante é movido para cima, todos os outros se movem para baixo, eventualmente para zero. Quando um é movido para baixo, os outros sobem. O total deve sempre ser 100. Portanto, aqui os controles deslizantes têm vários valores, mas totalizam 100%:
----O------ 40
O---------- 0
--O-------- 20
--O-------- 20
--O-------- 20
Se o primeiro controle deslizante for UP de 40 para 70, os outros deverão mover o valor DOWN (à medida que o controle deslizante é arrastado). Observe que três controles deslizantes foram alterados de 20 para 10 e um permaneceu em zero, pois não pode diminuir.
-------O--- 70
O---------- 0
-O--------- 10
-O--------- 10
-O--------- 10
É claro que quando qualquer controle deslizante atinge 0 ou 100, ele não pode se mover mais, e é aí que minha cabeça realmente começa a doer. Portanto, se um controle deslizante se move mais alto, os outros se movem mais baixo, mas quando algum deles chega a zero, apenas os demais que ainda não atingiram o zero podem se mover mais baixo.
Estou perguntando isso aqui, pois esta questão é específica para o algoritmo, não para a implementação. FWIW, a plataforma é Android Java, mas isso não é especialmente relevante.
A abordagem adotada com minha primeira punhalada foi calcular a alteração percentual do controle deslizante que se moveu. Dividi essa alteração e a apliquei (na outra direção) aos outros valores do controle deslizante. O problema, porém, é que, usando porcentagens e multiplicando, se algum controle deslizante chegar a zero, ele nunca poderá ser aumentado novamente de zero - o resultado líquido disso é que controles deslizantes individuais ficam presos em zero. Usei controles deslizantes com um intervalo de 0 a 1.000.000 para evitar problemas de arredondamento e isso parece ser útil, mas ainda não criei um algoritmo que lide bem com todos os cenários.
fonte
Respostas:
Algoritmo Ganancioso
Quando um controle deslizante se move para cima (para baixo), todos os outros precisam se mover para baixo (para cima). Cada um tem algum espaço em que pode se mover (para baixo - sua posição, para cima: posição 100).
Portanto, quando um controle deslizante se move, pegue os outros, classifique-os pelo espaço em que eles podem se mover e simplesmente percorra-os.
Em cada iteração, mova o controle deslizante na direção necessária por (total para mover para a esquerda / controles deslizantes para a esquerda na fila) ou a distância que ele pode se mover, o que for menor.
Isso é linear em complexidade (já que você pode usar a mesma fila ordenada repetidamente, depois que ela tiver sido classificada).
Nesse cenário, nenhum controle deslizante fica preso, todos tentam se mover o máximo que podem, mas apenas até a parte justa.
Movimento ponderado
Uma abordagem diferente seria ponderar a mudança que eles precisam fazer. Eu acho que foi isso que você tentou fazer, a julgar pelo seu sliders "fique preso no zero". IMHO isso é mais natural, você só precisa fazer mais ajustes.
Especulando novamente, eu diria que você tenta ponderar os movimentos de diferentes controles deslizantes pela posição deles (isso se traduziria diretamente no problema de zero). No entanto, observe que você pode visualizar a posição do controle deslizante de diferentes direções - desde o início ou até o final. Se você ponderar por posição desde o início ao diminuir e posição do fim ao aumentar, evite seu problema.
Isso é bastante semelhante em terminologia à parte anterior - não pondere o movimento a ser feito pela posição dos controles deslizantes, o peso pelo espaço que eles deixaram para se mover nessa direção.
fonte
A abordagem que eu adotaria é um pouco diferente e envolve o uso de uma representação interna diferente de cada controle deslizante.
cada controle deslizante pode assumir qualquer valor entre 0..100 (X), que é usado como um fator de ponderação para esse controle deslizante (não uma%)
some todos os valores do controle deslizante para obter o valor total (T)
para determinar o valor exibido de cada controle deslizante, use ROUND (X * 100 / T)
quando um controle deslizante é movido para cima ou para baixo, você altera apenas o valor do controle deslizante ; a ponderação para esse controle deslizante aumentará ou diminuirá em relação a todos os outros controles deslizantes, e o cálculo acima garantirá que a alteração em todos os outros controles deslizantes seja espalhada o mais uniformemente possível.
fonte
Acho que você está complicando demais as coisas tentando ajustar o valor atual em uma porcentagem da alteração do controle deslizante 'movido', que fornece porcentagens de porcentagens, o que está introduzindo erros de arredondamento.
Como você sabe que está apenas lidando com um valor total de 100, eu manteria as coisas como números inteiros e trabalharia inversamente a partir dos 100, evitando qualquer confusão séria com o arredondamento. (No exemplo abaixo, eu ligo para qualquer arredondamento como números inteiros no final)
Minha técnica seria definir os controles deslizantes como 0-100 simples. Subtraia o valor 'novo' de 100 para calcular quanto redistribuir, espalhe-o entre os outros controles deslizantes de acordo com o peso e depois limpe)
Tanto quanto sei, este não é um código Android válido: p
Isso deve manipular intrinsecamente qualquer valor de 0 ou 100
fonte
E a abordagem de Round Robin? Crie uma transação que garanta que a agregação de valor a um controle deslizante seja reduzida em relação a seus pares. e vice versa.
Toda vez que uma mudança de controle deslizante executa a transação com um controle deslizante de ponto diferente (eu criaria um iterador que retornaria o controle deslizante de ponto). Se o controle deslizante de ponto for zero, prossiga para o próximo.
fonte
Apenas para elaborar a excelente resposta do Greedy Algorithm de @Ordous. Aqui está um detalhamento das etapas.
fonte
Uma técnica simples é calcular porcentagens dos valores do controle deslizante em relação à soma dos valores do controle deslizante e reatribuir os valores do controle deslizante às respectivas porcentagens calculadas. desta forma, os valores dos controles deslizantes serão reajustados, por exemplo,
Embora ele introduza um erro de arredondamento, ele pode ser tratado caso seja necessário que os valores dos sliders sejam exatamente e sempre somados 100.
Eu configurei um violino para demonstrar isso usando angularjs. Por favor, visite demo
fonte