Ontem eu estava emparelhando as meias da roupa limpa e descobri que a maneira como estava fazendo isso não é muito eficiente. Eu estava fazendo uma pesquisa ingênua - pegando uma meia e "iterando" a pilha para encontrar seu par. Isto requer a iteração n / 2 * n / 4 = n 2 /8 meias, em média.
Como cientista da computação, estava pensando no que poderia fazer? A classificação (de acordo com tamanho / cor / ...) obviamente veio à mente para obter uma solução O (NlogN).
Hashing ou outras soluções não no local não são uma opção, porque não consigo duplicar minhas meias (embora possa ser bom).
Então, a questão é basicamente:
Dada uma pilha de n
pares de meias, contendo 2n
elementos (suponha que cada meia tenha exatamente um par correspondente), qual é a melhor maneira de combiná-las de maneira eficiente com espaço extra logarítmico? (Acredito que me lembro dessa quantidade de informações, se necessário.)
Aprecio uma resposta que aborda os seguintes aspectos:
- Uma solução teórica geral para um grande número de meias.
- O número real de meias não é tão grande, não acredito na minha esposa e tenho mais de 30 pares. (E é bastante fácil distinguir entre minhas meias e as dela; isso também pode ser usado?)
- É equivalente ao problema de distinção de elementos ?
waitpid
para que, como pai ou mãe, você não esteja nem mesmo escolhendo meias?Respostas:
Soluções de classificação foram propostas, mas a classificação é um pouco demais : não precisamos de ordem; nós apenas precisamos de grupos de igualdade .
Portanto, o hash seria suficiente (e mais rápido).
Esse tipo de particionamento de hash recursivo está realmente sendo feito pelo SQL Server quando ele precisa ingressar ou agregar hash em grandes conjuntos de dados. Ele distribui seu fluxo de entrada de construção em muitas partições independentes. Esse esquema é escalonado para quantidades arbitrárias de dados e várias CPUs linearmente.
Você não precisa de particionamento recursivo se conseguir encontrar uma chave de distribuição (chave de hash) que forneça intervalos suficientes para que cada intervalo seja pequeno o suficiente para ser processado rapidamente. Infelizmente, acho que as meias não têm essa propriedade.
Se cada meia tivesse um número inteiro chamado "PairID", seria possível distribuí-los facilmente em 10 baldes de acordo com
PairID % 10
(o último dígito).A melhor partição do mundo real que consigo pensar é criar um retângulo de pilhas : uma dimensão é cor, a outra é o padrão. Por que um retângulo? Porque precisamos de O (1) acesso aleatório a pilhas. (Um cubóide 3D também funcionaria, mas isso não é muito prático.)
Atualizar:
E o paralelismo ? Vários seres humanos podem combinar as meias mais rápido?
E o problema da distinção de elementos ? Como afirma o artigo, o problema de distinção de elementos pode ser resolvido
O(N)
. É o mesmo para o problema das meias (tambémO(N)
, se você precisar de apenas uma etapa de distribuição (propus várias etapas apenas porque os humanos são ruins em cálculos - uma etapa é suficiente se você distribuirmd5(color, length, pattern, ...)
, ou seja, um hash perfeito de todos os atributos)).Claramente, não se pode ir mais rápido do que
O(N)
, portanto, atingimos o limite inferior ideal .Embora as saídas não sejam exatamente as mesmas (em um caso, apenas um booleano. No outro caso, os pares de meias), as complexidades assintóticas são as mesmas.
fonte
Como a arquitetura do cérebro humano é completamente diferente de uma CPU moderna, essa questão não faz sentido prático.
Os seres humanos podem conquistar os algoritmos da CPU usando o fato de que "encontrar um par correspondente" pode ser uma operação para um conjunto que não é muito grande.
Meu algoritmo:
Pelo menos é isso que estou usando na vida real e acho muito eficiente. A desvantagem é que requer uma superfície plana, mas geralmente é abundante.
fonte
Caso 1 : Todas as meias são idênticas (a propósito, é isso que faço na vida real).
Escolha dois deles para formar um par. Tempo constante.
Caso 2 : Há um número constante de combinações (propriedade, cor, tamanho, textura, etc.).
Use classificação de base . Isso é apenas tempo linear, pois a comparação não é necessária.
Caso 3 : O número de combinações não é conhecido antecipadamente (caso geral).
Temos que fazer uma comparação para verificar se duas meias vêm em pares. Escolha um dos
O(n log n)
algoritmos de classificação com base em comparação.No entanto, na vida real, quando o número de meias é relativamente pequeno (constante), esses algoritmos teoricamente ótimos não funcionam bem. Pode levar ainda mais tempo que a pesquisa seqüencial, que teoricamente requer tempo quadrático.
fonte
Resposta não algorítmica, mas "eficiente" quando o faço:
passo 1) descarte todas as meias existentes
passo 2) vá ao Walmart e compre-os em pacotes de 10 - n de branco e m de preto. Não há necessidade de outras cores na vida cotidiana.
No entanto, de vez em quando, tenho que fazer isso de novo (meias perdidas, meias danificadas etc.), e odeio descartar meias perfeitamente boas com muita frequência (e eu desejava que elas continuassem vendendo a mesma referência de meias!), Então eu tirei recentemente uma abordagem diferente.
Resposta algorítmica:
Considere que, se você desenhar apenas uma meia para a segunda pilha de meias, como está fazendo, suas chances de encontrar a meia correspondente em uma pesquisa ingênua são bastante baixas.
Por que cinco? Geralmente, os humanos são bons em lembrar entre cinco e sete elementos diferentes na memória de trabalho - um pouco como o equivalente humano de uma pilha RPN - cinco é um padrão seguro.
Pegue um na pilha de 2n-5.
Agora, procure uma correspondência (correspondência de padrão visual - os humanos são bons nisso com uma pilha pequena) dentro das cinco que você desenhou, se você não encontrar uma, adicione-a às suas cinco.
Continue escolhendo aleatoriamente as meias da pilha e compare com as suas meias 5 + 1 para uma partida. À medida que sua pilha cresce, isso reduz seu desempenho, mas aumenta suas chances. Muito mais rapido.
Sinta-se à vontade para anotar a fórmula e calcular quantas amostras você precisa para obter 50% de chance de uma partida. IIRC é uma lei hipergeométrica.
Faço isso todas as manhãs e raramente preciso de mais de três empates - mas tenho
n
pares semelhantes (cerca de 10, mais ou menos os perdidos) dem
meias brancas em forma. Agora você pode estimar o tamanho da minha pilha de ações :-)BTW , eu descobri que a soma dos custos de transação para classificar todas as meias toda vez que eu precisava de um par era muito menor do que fazer isso uma vez e amarrar as meias. Um just-in-time funciona melhor porque então você não precisa amarrar as meias, e também há um retorno marginal decrescente (ou seja, você continua procurando essas duas ou três meias que quando estão na lavanderia e que você precisa para terminar de combinar suas meias e você perde tempo com isso).
fonte
O que faço é pegar a primeira meia e colocá-la no chão (digamos, na beirada da pia). Então pego outra meia e verifico se é a mesma que a primeira. Se for, eu removo os dois. Caso contrário, coloquei ao lado da primeira meia. Depois pego a terceira meia e a comparo com as duas primeiras (se ainda estiverem lá). Etc.
Essa abordagem pode ser facilmente implementada em uma matriz, assumindo que "remover" meias seja uma opção.Na verdade, você nem precisa "remover" as meias. Se você não precisar classificar as meias (veja abaixo), basta movê-las e acabar com uma matriz que tenha todas as meias organizadas em pares na matriz.Supondo que a única operação para meias seja comparar para igualdade, esse algoritmo ainda é basicamente um algoritmo n 2 , embora eu não conheça o caso médio (nunca aprendi a calcular isso).
A classificação, obviamente, melhora a eficiência, especialmente na vida real, onde você pode "inserir" facilmente uma meia entre duas outras meias. Na computação, o mesmo poderia ser alcançado por uma árvore, mas isso é espaço extra. E, é claro, estamos de volta ao NlogN (ou um pouco mais, se houver várias meias iguais pelos critérios de classificação, mas não do mesmo par).
Fora isso, não consigo pensar em nada, mas esse método parece ser bastante eficiente na vida real. :)
fonte
Isso está fazendo a pergunta errada. A pergunta certa a fazer é: por que estou gastando tempo classificando meias? Quanto custa anualmente, quando você valoriza seu tempo livre para X unidades monetárias de sua escolha?
E, na maioria das vezes, esse não é apenas um tempo livre, é o tempo livre da manhã , que você pode passar na cama, tomar um café ou sair um pouco mais cedo e não ficar preso no trânsito.
Muitas vezes, é bom dar um passo atrás e pensar em uma maneira de contornar o problema.
E existe um caminho!
Encontre uma meia que você gosta. Leve em consideração todos os recursos relevantes: cores em diferentes condições de iluminação, qualidade e durabilidade gerais, conforto em diferentes condições climáticas e absorção de odores. Também importante é que eles não devem perder elasticidade no armazenamento; portanto, os tecidos naturais são bons e devem estar disponíveis em uma embalagem plástica.
É melhor se não houver diferença entre as meias esquerda e direita, mas não for crítico. Se as meias são esquerda-direita simétricas, encontrar um par é uma operação O (1) e classificar as meias é uma operação aproximada O (M), em que M é o número de locais em sua casa que você deixou com meias, idealmente alguns pequeno número constante.
Se você escolheu um par sofisticado com meia esquerda e direita diferente, ao fazer uma ordenação de caçamba cheia para as caçambas pé esquerdo e direito, use O (N + M), onde N é o número de meias e M é o mesmo que acima. Outra pessoa pode dar a fórmula para iterações médias de encontrar o primeiro par, mas o pior caso para encontrar um par com pesquisa cega é N / 2 + 1, o que torna astronomicamente improvável o caso de N. razoável. Isso pode ser acelerado usando imagem avançada algoritmos de reconhecimento e heurísticas, ao digitalizar a pilha de meias não classificadas com o Mk1 Eyeball .
Portanto, um algoritmo para obter a eficiência de emparelhamento de meias O (1) (assumindo uma meia simétrica) é:
Você precisa estimar quantos pares de meias precisará para o resto da sua vida, ou talvez até se aposentar e mudar para climas mais quentes sem precisar usar meias novamente. Se você é jovem, também pode estimar quanto tempo leva para que todos tenhamos robôs de classificação de meias em nossas casas, e todo o problema se torna irrelevante.
Você precisa descobrir como encomendar a meia selecionada a granel, quanto custa e como ela é entregue.
Encomende as meias!
Livre-se de suas meias velhas.
Um passo alternativo 3 envolveria a comparação dos custos de compra da mesma quantidade de meias talvez mais baratas, alguns pares de cada vez ao longo dos anos e a adição do custo da classificação de meias, mas acredite nisso: comprar a granel é mais barato! Além disso, as meias no armazenamento aumentam de valor à taxa de inflação dos preços das ações, que é mais do que você obteria em muitos investimentos. Por outro lado, também há custo de armazenamento, mas as meias realmente não ocupam muito espaço na prateleira superior de um armário.
Problema resolvido. Portanto, compre meias novas, jogue / doe as velhas e viva feliz para sempre, sabendo que você está economizando tempo e dinheiro todos os dias pelo resto da vida.
fonte
O limite teórico é O (n) porque você precisa tocar em cada meia (a menos que algumas já estejam emparelhadas de alguma forma).
Você pode obter O (n) com a classificação radix . Você só precisa escolher alguns atributos para os buckets.
Se você pode escolher um número limitado de atributos, mas atributos suficientes que podem identificar cada par exclusivamente, você deve fazer isso em O (k * n), que é O (n) se considerarmos que k é limitado.
fonte
$
personagem, para fazer com que suas coisas pareçam código-y.Como uma solução prática:
Se você tiver 1000 meias, com 8 cores e uma distribuição média, poderá fazer 4 pilhas de cada 125 meias em tempo c * n. Com um limite de 5 meias, você pode classificar todas as pilhas em 6 corridas. (Contando 2 segundos para jogar uma meia na pilha certa, você levará pouco menos de 4 horas.)
Se você tiver apenas 60 meias, 3 cores e 2 tipos de meias (sua / da sua esposa), poderá classificar cada pilha de 10 meias em 1 corrida (novamente o limiar = 5). (Contando 2 segundos, você levará 2 minutos).
A classificação inicial do balde agilizará seu processo, porque divide suas n meias em k baldes no
c*n
tempo, para que você só precise fazer oc*n*log(k)
trabalho. (Não levando em consideração o limite). Então, apesar de tudo, você fazn*c*(1 + log(k))
trabalho, onde c é a hora de jogar uma meia em uma pilha.Essa abordagem será favorável em comparação com qualquer
c*x*n + O(1)
método aproximadamente desde quelog(k) < x - 1
.Na ciência da computação, isso pode ser útil: temos uma coleção de n coisas , uma ordem nelas (comprimento) e também uma relação de equivalência (informações extras, por exemplo, a cor das meias). A relação de equivalência nos permite fazer uma partição da coleção original e, em todas as classes de equivalência, nossa ordem ainda é mantida. O mapeamento de uma coisa para sua classe de equivalência pode ser feito em O (1), portanto, apenas O (n) é necessário para atribuir cada item a uma classe. Agora usamos nossas informações extras e podemos proceder de qualquer maneira para classificar todas as classes. A vantagem é que os conjuntos de dados já são significativamente menores.
O método também pode ser aninhado, se tivermos várias relações de equivalência -> criar pilhas de cores, do que dentro de cada partição de pilha na textura, do que classificar no comprimento. Qualquer relação de equivalência que crie uma partição com mais de 2 elementos que tenham tamanho uniforme trará uma melhoria na velocidade da classificação (desde que possamos atribuir diretamente uma meia à pilha), e a classificação poderá ocorrer muito rapidamente em conjuntos de dados menores.
fonte
Você está tentando resolver o problema errado.
Solução 1: Sempre que colocar meias sujas no cesto de roupa suja, amarre-as em um pequeno nó. Dessa forma, você não terá que fazer nenhuma classificação após a lavagem. Pense nisso como registrar um índice em um banco de dados Mongo. Um pouco de trabalho pela frente para algumas economias de CPU no futuro.
Solução 2: se for inverno, você não precisará usar meias iguais. Nós somos programadores. Ninguém precisa saber, desde que funcione.
Solução 3: Espalhe o trabalho. Você deseja executar um processo de CPU tão complexo de forma assíncrona, sem bloquear a interface do usuário. Pegue essa pilha de meias e coloque-as em um saco. Procure apenas um par quando precisar. Dessa forma, a quantidade de trabalho necessária é muito menos perceptível.
Espero que isto ajude!
fonte
Esta questão é realmente profundamente filosófica. No fundo, é sobre se o poder das pessoas em resolver problemas (o "wetware" de nossos cérebros) é equivalente ao que pode ser realizado por algoritmos.
Um algoritmo óbvio para classificação de meias é:
Agora, a ciência da computação nesse problema trata das etapas
Os seres humanos usarão várias estratégias para efetuá-las. A memória humana é associativa , algo como uma tabela de hash em que conjuntos de recursos de valores armazenados são combinados com os próprios valores correspondentes. Por exemplo, o conceito de "carro vermelho" é mapeado para todos os carros vermelhos de que uma pessoa é capaz de se lembrar. Alguém com uma memória perfeita possui um mapeamento perfeito. A maioria das pessoas é imperfeita nesse aspecto (e na maioria das outras). O mapa associativo tem uma capacidade limitada. Os mapeamentos podem bipar fora da existência sob várias circunstâncias (uma cerveja a mais), ser gravada por engano ("eu pensei que o nome dela era Betty, não Nettie"), ou nunca ser substituída, apesar de observarmos que a verdade mudou (o "carro do pai" evoca "Firebird laranja" quando sabíamos que ele havia trocado isso pelo Camaro vermelho).
No caso de meias, recordar perfeitamente significa olhar para uma meia
s
sempre produz a memória de seu irmãot
, incluindo informações suficientes (onde está na tábua de passar) para localizart
em tempo constante. Uma pessoa com memória fotográfica realiza 1 e 2 em tempo constante, sem falhas.Alguém com memória menos que perfeita pode usar algumas classes de equivalência de senso comum com base em recursos dentro de sua capacidade de rastrear: tamanho (papai, mamãe, bebê), cor (esverdeado, avermelhado etc.), padrão (argyle, comum etc.) , estilo (footie, até o joelho, etc.). Portanto, a tábua de passar seria dividida em seções para as categorias. Isso geralmente permite que a categoria seja localizada em tempo constante pela memória, mas é necessária uma pesquisa linear na categoria "bucket".
Alguém sem memória ou imaginação (desculpe) apenas mantém as meias em uma pilha e faz uma pesquisa linear de toda a pilha.
Uma aberração pura pode usar rótulos numéricos para pares, como alguém sugeriu. Isso abre a porta para um pedido total, o que permite que o ser humano use exatamente os mesmos algoritmos que podemos usar com uma CPU: pesquisa binária, árvores, hashes etc.
Portanto, o "melhor" algoritmo depende das qualidades do wetware / hardware / software que o está executando e da nossa vontade de "trapacear" impondo uma ordem total aos pares. Certamente, o "melhor" meta- algoritmo é contratar o melhor classificador de meias do mundo: uma pessoa ou máquina que pode adquirir e armazenar rapidamente um grande conjunto N de conjuntos de atributos de meia em uma memória associativa 1-1 com pesquisa constante, inserir, e apague. Pessoas e máquinas como essa podem ser adquiridas. Se você tiver um, poderá emparelhar todas as meias no tempo O (N) para N pares, o que é ideal. As tags de pedido total permitem que você use o hash padrão para obter o mesmo resultado com um computador humano ou de hardware.
fonte
Custo: Meias em movimento -> altas, encontrar / pesquisar meias em linha -> pequenas
O que queremos fazer é reduzir o número de movimentos e compensar com o número de pesquisas. Além disso, podemos utilizar o ambiente multithreded do Homo Sapiens para armazenar mais coisas no cache de decisão.
X = Seu, Y = Seus cônjuges
Da pilha A de todas as meias:
Escolha duas meias, coloque a meia X correspondente na linha X e a meia Y na linha Y na próxima posição disponível.
Faça até que A esteja vazio.
Para cada linha X e Y
Escolha a primeira meia da fila, procure ao longo da linha até encontrar a meia correspondente.
Coloque na linha final correspondente de meias.
Opcionalmente, na etapa um, você escolhe duas meias dessa linha em vez de duas, pois a memória do cache é grande o suficiente para que possamos identificar rapidamente se uma das meias corresponde à atual na linha que você está observando. Se você tiver a sorte de ter três braços, poderá analisar três meias ao mesmo tempo, uma vez que a memória do objeto é grande o suficiente.
Faça até X e Y estarem vazios.
Feito
No entanto, como isso tem complexidade semelhante à classificação, o tempo gasto é muito menor devido às velocidades de E / S (meias móveis) e pesquisa (pesquisando na linha por uma meia).
fonte
Aqui está um limite inferior Omega (n log n) no modelo baseado em comparação. (A única operação válida é comparar duas meias.)
Suponha que você saiba que suas meias 2n estão organizadas desta maneira:
p 1 p 2 p 3 ... p n p f (1) p f (2) ... p f (n)
onde f é uma permutação desconhecida do conjunto {1,2, ..., n}. Saber disso não pode dificultar o problema. Existem n! saídas possíveis (correspondências entre a primeira e a segunda metade), o que significa que você precisa de comparações log (n!) = Omega (n log n). Isso pode ser obtido por classificação.
Como você está interessado em conexões com o problema de distinção de elementos: provar que o Omega (n log n) vinculado à distinção de elementos é mais difícil, porque a saída é binária yes / no. Aqui, a saída deve ser uma correspondência e o número de saídas possíveis é suficiente para obter um limite decente. No entanto, há uma variante conectada à distinção de elemento. Suponha que você receba 2n meias e pergunte-se se elas podem ser unicamente combinadas. Você pode obter uma redução de ED enviando (a 1 , a 2 , ..., a n ) para (a 1 , a 1 , a 2 , a 2 , ..., a n , a n ). (Entre parênteses, a prova de dureza da ED é muito interessante, via topologia.)
Eu acho que deveria haver um Omega (n 2 ) vinculado ao problema original se você permitir apenas testes de igualdade. Minha intuição é: considere um gráfico em que você adiciona uma aresta após um teste e defenda que, se o gráfico não for denso, a saída não será determinada exclusivamente.
fonte
É assim que eu realmente faço isso, para p pares de meias ( n = 2p meias individuais):
O pior cenário desse esquema é que cada par de meias é diferente o suficiente para ser correspondido exatamente e que as primeiras meias n / 2 que você escolhe são todas diferentes. Esse é o seu cenário de O (n 2 ) e é extremamente improvável. Se o número de tipos únicos de meias t for menor que o número de pares p = n / 2 , e as meias de cada tipo forem iguais o suficiente (geralmente em termos relacionados ao desgaste), qualquer meia desse tipo poderá ser emparelhada com qualquer outro, então como eu inferido acima, o número máximo de meias que você nunca vai ter de comparar é t , após o qual o próximo você puxa vontadecombinar uma das meias não emparelhadas. Esse cenário é muito mais provável na gaveta média do que no pior caso e reduz a complexidade do pior caso a O (n * t), onde geralmente t << n .
fonte
Abordagem do mundo real:
O mais rápido possível, remova as meias da pilha não classificada, uma de cada vez, e coloque-as em pilhas à sua frente. As estacas devem ser dispostas de maneira um pouco eficiente no espaço, com todas as meias apontando na mesma direção; o número de pilhas é limitado pela distância que você pode alcançar facilmente. A seleção de uma pilha na qual colocar uma meia deve ser - o mais rápido possível - colocando uma meia em uma pilha de meias aparentemente semelhantes; o erro ocasional tipo I (colocando uma meia em uma pilha à qual não pertence) ou tipo II (colocando uma meia em sua própria pilha quando houver uma pilha existente de meias semelhantes) pode ser tolerado - a consideração mais importante é a velocidade .
Quando todas as meias estiverem empilhadas, passe rapidamente pelas pilhas com várias meias, criando pares e removendo-os (eles estão indo para a gaveta). Se houver meias sem correspondência na pilha, empilhe-as novamente da melhor forma possível (dentro da restrição o mais rápido possível). Quando todas as pilhas de meias múltiplas tiverem sido processadas, combine as meias pareadas restantes que não foram emparelhadas devido a erros do tipo II. Whoosh, você terminou - e eu tenho muitas meias e não as lavo até que uma grande fração esteja suja. Outra observação prática: abro a parte de cima de uma meia sobre a outra, aproveitando suas propriedades elásticas, para que elas fiquem juntas enquanto são transportadas para a gaveta e enquanto estão na gaveta.
fonte
De sua pergunta, é claro que você não tem muita experiência real com lavanderia :). Você precisa de um algoritmo que funcione bem com um pequeno número de meias não emparelhadas.
As respostas até agora não fazem bom uso de nossos recursos de reconhecimento de padrões humanos. O jogo de Set fornece uma pista de como fazer isso bem: coloque todas as meias em um espaço bidimensional para que você possa reconhecê-las bem e alcançá-las facilmente com as mãos. Isso limita você a uma área de aproximadamente 120 * 80 cm. A partir daí, selecione os pares que você reconhece e remova-os. Coloque meias extras no espaço livre e repita. Se você lava para pessoas com meias facilmente reconhecíveis (crianças pequenas vêm à mente), pode fazer uma classificação radical selecionando essas meias primeiro. Esse algoritmo funciona bem apenas quando o número de meias únicas é baixo
fonte
Pegue uma primeira meia e coloque-a sobre uma mesa. Agora escolha outra meia; se corresponder ao primeiro escolhido, coloque-o em cima do primeiro. Caso contrário, coloque-o sobre a mesa a uma pequena distância do primeiro. Escolha uma terceira meia; se ele corresponder a um dos dois anteriores, coloque-o em cima deles ou coloque-o a uma pequena distância do terceiro. Repita o procedimento até pegar todas as meias.
fonte
Para dizer o quão eficiente é parear meias de uma pilha, precisamos primeiro definir a máquina, porque o emparelhamento não é feito nem por uma máquina de turing nem por uma máquina de acesso aleatório, que normalmente são usadas como base para uma análise algorítmica.
A máquina
A máquina é uma abstração de um elemento do mundo real chamado ser humano. É capaz de ler do ambiente através de um par de olhos. E nosso modelo de máquina é capaz de manipular o ambiente usando 2 braços. As operações lógicas e aritméticas são calculadas usando nosso cérebro (espero ;-)).
Também devemos considerar o tempo de execução intrínseco das operações atômicas que podem ser realizadas com esses instrumentos. Devido a restrições físicas, as operações realizadas por um braço ou olho têm complexidade de tempo não constante. Isso ocorre porque não podemos mover uma pilha infinitamente grande de meias com um braço, nem um olho pode ver a meia superior em uma pilha infinitamente grande de meias.
No entanto, a física mecânica também nos oferece alguns benefícios. Não estamos limitados a mover no máximo uma meia com um braço. Podemos mover um par inteiro deles de uma só vez.
Portanto, dependendo da análise anterior, as seguintes operações devem ser usadas em ordem decrescente:
Também podemos usar o fato de que as pessoas só têm uma quantidade muito limitada de meias. Portanto, uma modificação ambiental pode envolver todas as meias da pilha.
O algoritmo
Então aqui está a minha sugestão:
A operação 4 é necessária, porque ao espalhar meias pelo chão, algumas podem esconder outras. Aqui está a análise do algoritmo:
A análise
O algoritmo termina com alta probabilidade. Isso se deve ao fato de que não é possível encontrar pares de meias na etapa número 2.
Para a análise em tempo de execução a seguir de emparelhamento de
n
pares de meias, supomos que pelo menos metade das2n
meias não esteja oculta após a etapa 1. Portanto, no caso médio, podemos encontrarn/2
pares. Isso significa que o loop é executado na etapa 4O(log n)
vezes. O passo 2 é executadoO(n^2)
vezes. Para que possamos concluir:O(ln n + n)
modificações ambientais (etapa 1O(ln n)
mais escolher cada par de meias do chão)O(n^2)
leituras ambientais da etapa 2O(n^2)
operações lógicas e aritméticas para comparar uma meia com outra na etapa 2Portanto, temos uma complexidade total do tempo de execução de
O(r*n^2 + w*(ln n + n))
onder
ew
são os fatores para as operações de leitura e gravação ambiental, respectivamente, para uma quantidade razoável de meias. O custo das operações lógicas e aritméticas é omitido, porque supomos que é necessária uma quantidade constante de operações lógicas e aritméticas para decidir se 2 meias pertencem ao mesmo par. Isso pode não ser viável em todos os cenários.fonte
fonte
Saí com outra solução que não prometeria menos operações, nem menos consumo de tempo, mas deve-se tentar ver se pode ser uma heurística suficientemente boa para fornecer menos consumo de tempo em grandes séries de emparelhamento de meias.
Condições prévias: Não há garantia de que existem as mesmas meias. Se eles são da mesma cor, isso não significa que eles tenham o mesmo tamanho ou padrão. As meias são aleatoriamente embaralhadas. Pode haver um número ímpar de meias (algumas estão faltando, não sabemos quantas). Prepare-se para lembrar uma variável "index" e defina-a como 0.
O resultado terá uma ou duas pilhas: 1. "correspondido" e 2. "ausente"
Heurística:
Além disso, pode-se adicionar verificação de meias danificadas também, como se a remoção delas. Pode ser inserido entre 2 e 3 e entre 13 e 14.
Estou ansioso para ouvir sobre quaisquer experiências ou correções.
fonte
Quando ordeno as meias, faço uma classificação aproximada , deixando as meias perto de outras da mesma cor / tipo de padrão. Exceto no caso em que vejo uma correspondência exata no / próximo ao local em que estou prestes a largar a meia, extraio o par nesse momento.
Quase todos os outros algoritmos (incluindo a resposta de pontuação mais alta por usr ) classificam e removem os pares. Acho que, como humano, é melhor minimizar o número de meias sendo consideradas ao mesmo tempo.
Eu faço isso por:
Isso tira proveito da capacidade humana de fazer a correspondência difusa no tempo O (1), o que é um pouco equivalente ao estabelecimento de um mapa de hash em um dispositivo de computação.
Ao puxar as meias distintivas primeiro, você deixa espaço para "ampliar" os recursos que são menos distintos, para começar.
Depois de eliminar o fluro colorido, as meias com listras e os três pares de meias longas, você pode acabar usando principalmente meias brancas, classificadas de acordo com o desgaste.
Em algum momento, as diferenças entre as meias são pequenas o suficiente para que outras pessoas não notem a diferença, e não é necessário nenhum esforço adicional.
fonte
Sempre que você pegar uma meia, coloque-a em um só lugar. Em seguida, a próxima meia que você pegar, se não corresponder à primeira, coloque-a ao lado da primeira. Se isso acontecer, há um par. Dessa forma, não importa quantas combinações existem, e existem apenas duas possibilidades para cada meia que você escolhe - ou ela tem uma correspondência que já está na sua coleção de meias ou não, o que significa que você adicione-o a um local na matriz.
Isso também significa que você quase certamente nunca terá todas as suas meias na matriz, porque elas serão removidas à medida que forem correspondidas.
fonte
Considere uma tabela de tamanho 'N'.
Se assumirmos a distribuição normal, o número estimado de 'inserções' com pelo menos uma meia mapeada para um bucket é NlogN (ou seja, todos os buckets estão cheios)
Eu derivara isso como parte de outro quebra-cabeça, mas ficaria feliz em provar que estou errado. Aqui está o meu artigo sobre o mesmo
Deixe 'N' corresponder a um limite superior aproximado do número de cores / padrão únicos de meias que você possui.
Depois de ter uma colisão (aka: uma partida), basta remover esse par de meias. Repita o mesmo experimento com o próximo lote de meias NlogN. A vantagem disso é que você pode fazer comparações paralelas ao NlogN (resolução de colisão) por causa da maneira como a mente humana funciona. :-)
fonte
As meias, sejam reais ou alguma estrutura de dados análoga, seriam fornecidas em pares.
A resposta mais simples é antes de permitir que o par seja separado, uma única estrutura de dados para o par deveria ter sido inicializada, contendo um ponteiro para a meia esquerda e direita, permitindo assim que as meias fossem referidas diretamente ou através de seu par. Uma meia também pode ser estendida para conter um ponteiro para seu parceiro.
Isso resolve qualquer problema de emparelhamento computacional removendo-o com uma camada de abstração.
Aplicando a mesma idéia ao problema prático de emparelhar meias, a resposta aparente é: não permita que suas meias sejam pareadas. As meias são fornecidas como um par, colocadas na gaveta como um par (talvez juntando-as), usadas como um par. Mas o ponto em que é possível desemparelhar é na lavadora, então tudo o que é necessário é um mecanismo físico que permita que as meias fiquem juntas e sejam lavadas com eficiência.
Existem duas possibilidades físicas:
Para um objeto de 'par' que mantém um ponteiro para cada meia, poderíamos ter um saco de pano que usamos para manter as meias juntas. Isso parece uma sobrecarga enorme.
Mas para cada meia manter uma referência à outra, existe uma solução interessante: um popper (ou um 'botão de pressão' se você for americano), como estes:
http://www.aliexpress.com/compare/compare-invisible-snap-buttons.html
Tudo o que você faz é ajuntar as meias logo depois de tirá-las e colocá-las no cesto de lavar roupa e, novamente, você removeu o problema de precisar emparelhá-las com uma abstração física do conceito de 'par'.
fonte
Se a operação "mover" for bastante cara e a operação "comparar" for barata, e você precisar mover todo o conjunto de qualquer maneira, para um buffer em que a pesquisa seja muito mais rápida do que no armazenamento original ... basta integrar a classificação no campo obrigatório. mover.
Eu achei que integrar o processo de classificação em pendurar para secar torna uma brisa. Eu preciso pegar cada meia de qualquer maneira e pendurá-la (mover) e não me custa nada pendurá-la em um local específico nas cordas. Agora, apenas para não forçar a pesquisa de todo o buffer (as cordas), escolho colocar as meias por cor / sombra. Mais escura à esquerda, mais brilhante à direita, frente mais colorida etc. Agora, antes de pendurar cada meia, olho na "vizinhança certa" se já existe uma correspondente - isso limita a "varredura" para 2-3 outras meias - e se for , Penduro o outro ao lado dele. Depois enrolo-os em pares, removendo das cordas, quando secos.
Agora, isso pode não parecer tão diferente de "formar pilhas por cor", sugerido pelas respostas principais, mas primeiro, não escolhendo pilhas discretas, mas intervalos, não tenho problema em classificar se "roxo" vai para a pilha "vermelha" ou "azul"; apenas vai entre. E então, integrando duas operações (travar para secar e classificar), a sobrecarga da classificação durante a suspensão é 10% do que seria uma classificação separada.
fonte
Acabei de emparelhar minhas meias agora e descobri que a melhor maneira de fazer isso é a seguinte:
Na pior das hipóteses, isso significa que você terá n / 2 baldes diferentes e terá n-2 determinações sobre o balde que contém o par da meia atual. Obviamente, esse algoritmo funciona bem se você tiver apenas alguns pares; Eu fiz isso com 12 pares.
Não é tão científico, mas funciona bem :)
fonte
Minha solução não corresponde exatamente aos seus requisitos, pois exige formalmente
O(n)
espaço "extra". No entanto, considerando minhas condições, é muito eficiente em minha aplicação prática. Portanto, acho que deveria ser interessante.Combinar com outra tarefa
A condição especial no meu caso é que eu não uso a máquina de secar, apenas penduro minhas roupas em um secador de roupas comum. Pendurar panos requer
O(n)
operações (a propósito, eu sempre considero um problema de empacotamento de lixeira aqui) e o problema, por sua natureza, requer o espaço "extra" linear. Quando tiro uma meia nova do balde, tente pendurá-la ao lado do par, se o par já estiver pendurado. Se é uma meia de um novo par, deixo algum espaço ao lado.Oracle Machine is Better ;-)
Obviamente, requer algum trabalho extra para verificar se a meia correspondente já está pendurada em algum lugar e renderizaria a solução
O(n^2)
com coeficiente1/2
para um computador. Mas, neste caso, o "fator humano" é realmente uma vantagem - eu geralmente consigoO(1)
identificar (quase ) muito rapidamente a meia correspondente se ela já estava pendurada (provavelmente está envolvido algum cache imperceptível no cérebro) - considere-a uma espécie de limitado "oracle" como no Oracle Machine ;-) Nós, os humanos, temos essas vantagens sobre as máquinas digitais em alguns casos ;-)Já quase
O(n)
!Assim, conectando o problema de emparelhar meias com o problema de pendurar panos, recebo
O(n)
"espaço extra" de graça e tenho uma solução que está quaseO(n)
no tempo, requer apenas um pouco mais de trabalho do que simples panos pendurados e permite acessar imediatamente par completo de meias mesmo em uma péssima segunda de manhã ... ;-)fonte
Espero poder contribuir com algo novo para esse problema. Percebi que todas as respostas negligenciam o fato de que existem dois pontos em que você pode executar o pré-processamento , sem diminuir o desempenho geral da lavanderia.
Além disso, não precisamos assumir um grande número de meias, mesmo para famílias grandes. As meias são retiradas da gaveta e desgastadas e depois jogadas em um local (talvez uma lixeira) onde ficam antes de serem lavadas. Embora eu não chamasse o bin bin de LIFO-Stack, eu diria que é seguro assumir que
Como todas as máquinas de lavar roupa que eu conheço são de tamanho limitado (independentemente de quantas meias você precisa lavar), e a randomização real ocorre na máquina de lavar, não importa quantas meias nós temos, sempre temos pequenos subconjuntos que quase não contêm singletons.
Nossas duas etapas de pré-processamento são "colocar as meias no varal" e "Tirar as meias do varal", o que temos que fazer para obter meias que não são apenas limpas, mas também secas. Assim como as máquinas de lavar, os varais são finitos e presumo que tenhamos toda a parte da linha em que colocamos nossas meias à vista.
Aqui está o algoritmo para put_socks_on_line ():
Não perca seu tempo movendo as meias ou procurando a melhor combinação, tudo isso deve ser feito em O (n), que também seria necessário para colocá-las na linha sem classificação. As meias ainda não estão emparelhadas, só temos vários grupos de similaridade em jogo. É útil termos um conjunto limitado de meias aqui, pois isso nos ajuda a criar grupos "bons" (por exemplo, se houver apenas meias pretas no conjunto de meias, agrupar por cores não seria o caminho a seguir).
Aqui está o algoritmo para take_socks_from_line ():
Devo ressaltar que, para melhorar a velocidade das etapas restantes, é aconselhável não escolher aleatoriamente a próxima meia, mas sequencialmente tirar meia após meia de cada cluster. Ambas as etapas de pré-processamento não levam mais tempo do que colocar as meias na linha ou na cesta, o que temos que fazer, não importa o que aconteça, portanto isso deve melhorar muito o desempenho da lavanderia.
Depois disso, é fácil executar o algoritmo de particionamento de hash. Normalmente, cerca de 75% das meias já estão emparelhadas, deixando-me com um subconjunto muito pequeno de meias, e esse subconjunto já está (um pouco) agrupado (não introduzo muita entropia na minha cesta após as etapas de pré-processamento). Outra coisa é que os clusters restantes tendem a ser pequenos o suficiente para serem manuseados de uma só vez, portanto, é possível retirar um cluster inteiro da cesta.
Aqui está o algoritmo para sort_remaining_clusters ():
Depois disso, restam apenas algumas meias. É aqui que introduzo meias anteriormente não emparelhadas no sistema e processo as meias restantes sem nenhum algoritmo especial - as meias restantes são muito poucas e podem ser processadas visualmente muito rapidamente.
Para todas as meias restantes, suponho que os colegas ainda não estejam lavados e os guardo para a próxima iteração. Se você registrar um crescimento de meias não emparelhadas ao longo do tempo (um "vazamento de meia"), verifique sua lixeira - ela pode ser aleatória (você tem gatos que dormem lá?)
Eu sei que esses algoritmos têm muitas suposições: uma lixeira que funciona como algum tipo de pilha LIFO, uma máquina de lavar normal limitada e um varal normal, limitado - mas isso ainda funciona com um número muito grande de meias.
Sobre o paralelismo: contanto que você jogue as duas meias na mesma lixeira, é possível paralelizar facilmente todas essas etapas.
fonte
Tomei medidas simples para reduzir meu esforço em um processo que leva tempo O (1).
Ao reduzir minhas entradas para um dos dois tipos de meias (meias brancas para recreação, meias pretas para o trabalho), só preciso determinar qual das duas meias tenho em mãos. (Tecnicamente, como nunca são lavados juntos, reduzi o processo para o tempo O (0).)
É necessário algum esforço inicial para encontrar as meias desejáveis e comprar em quantidade suficiente para eliminar a necessidade das meias existentes. Como eu havia feito isso antes da minha necessidade de meias pretas, meu esforço era mínimo, mas a milhagem pode variar.
Esse esforço inicial foi visto muitas vezes em códigos muito populares e eficazes. Os exemplos incluem # DEFININDO pi com várias casas decimais (existem outros exemplos, mas esse é o que vem à mente agora).
fonte
Crie uma tabela de hash que será usada para meias incomparáveis, usando o padrão como hash. Repita as meias uma a uma. Se a meia tiver uma correspondência de padrões na tabela de hash, tire-a da mesa e faça um par. Se a meia não corresponder, coloque-a na mesa.
fonte
O problema de classificar seus n pares de meias é O (n) . Antes de jogá-los no cesto de roupa suja , enfie o da esquerda para o da direita. Ao retirá-las, você corta a linha e coloca cada par na gaveta - 2 operações em n pares, então O (n).
Agora, a próxima pergunta é simplesmente se você lava sua própria roupa e sua esposa lava a dela. Esse é um problema provavelmente em um domínio de problemas completamente diferente . :)
fonte