web-dev-qa-db-fra.com

Comment coupler efficacement les chaussettes d'un tas?

Hier, je jumelais les chaussettes de la lessive propre et je me suis rendu compte que ce que je faisais n’est pas très efficace. Je faisais une recherche naïve - ramasser une chaussette et "itérer" la pile afin de trouver sa paire. Cela nécessite une itération sur n/2 * n/4 = n2/ 8 chaussettes en moyenne.

En tant qu'informaticien, je pensais à ce que je pouvais faire? Le tri (en fonction de la taille/couleur/...) est bien sûr venu à l’esprit pour obtenir une solution O(NlogN).

Le hachage ou d'autres solutions non-en place ne sont pas une option, car je ne suis pas en mesure de dupliquer mes chaussettes (bien que cela puisse être agréable si je le pouvais).

Donc, la question est fondamentalement:

Étant donné un tas de n paires de chaussettes contenant des éléments 2n (en supposant que chaque chaussette a exactement une paire correspondante), quel est le meilleur moyen de les coupler efficacement avec un espace supplémentaire logarithmique? (Je crois que je peux me souvenir de cette quantité d'informations si nécessaire.)

J'apprécierai une réponse qui aborde les aspects suivants:

  • Une solution générale théorique pour un grand nombre de chaussettes.
  • Le nombre réel de chaussettes n’est pas très élevé, je ne crois pas que mon épouse et moi-même avons plus de 30 paires. (Et il est assez facile de distinguer mes chaussettes des siennes; cela peut-il être utilisé aussi?)
  • Est-il équivalent au problème de distinction d'élément ?
3815
amit

Des solutions de tri ont été proposées, mais le tri est un peu trop: Nous n'avons pas besoin de commande; nous avons juste besoin de groupes d'égalité.

Donc hachage serait suffisant (et plus rapide).

  1. Pour chaque couleur de chaussettes, forme une pile. Parcourez toutes les chaussettes de votre panier d’entrée et répartissez-les sur les piles de couleurs.
  2. Parcourez chaque pile et distribuez-la selon une autre métrique (exemple: motif) dans le deuxième ensemble de piles
  3. Appliquez ce système de manière récursive jusqu'à ce que toutes les chaussettes soient réparties sur de très petites piles que vous pouvez traiter visuellement immédiatement

Ce type de partitionnement récursif de hachage est en fait effectué par SQL Server lorsqu'il doit hacher la jointure ou l'agrégat de hachage sur d'énormes ensembles de données. Il distribue son flux d'entrée de construction dans de nombreuses partitions indépendantes. Ce schéma s'adapte à des quantités arbitraires de données et à plusieurs processeurs de manière linéaire.

Vous n'avez pas besoin de partitionnement récursif si vous pouvez trouver une clé de distribution (clé de hachage) qui fournit suffisamment de compartiments pour que chaque compartiment soit suffisamment petit pour être traité très rapidement. Malheureusement, je ne pense pas que les chaussettes aient une telle propriété.

Si chaque chaussette avait un entier appelé "PairID", on pourrait facilement les répartir dans 10 compartiments selon PairID % 10 (le dernier chiffre).

Le meilleur partitionnement dans le monde réel auquel je puisse penser est de créer un rectangle de piles: une dimension est la couleur, l’autre est le motif. Pourquoi un rectangle? Parce que nous avons besoin de O(1) accès aléatoire aux piles. (Une 3D cuboïde fonctionnerait aussi, mais ce n'est pas très pratique.)


Mise à jour:

Qu'en est-il de parallelism? Plusieurs humains peuvent-ils faire correspondre les chaussettes plus rapidement?

  1. La stratégie de parallélisation la plus simple consiste à faire en sorte que plusieurs travailleurs prennent dans le panier d’entrée et mettent les chaussettes sur les piles. Cela ne fait qu'aggraver les choses: imaginez 100 personnes qui se disputent 10 piles. Les coûts de synchronisation (se manifestant par des collisions de mains et des communications humaines) détruisent l'efficacité et la vitesse (voir la Loi universelle sur la scalabilité !). Est-ce enclin à impasses? Non, car chaque travailleur n'a besoin d'accéder qu'à une pile à la fois. Avec un seul "verrou", il ne peut y avoir d’impasse. Livelocks pourrait être possible selon la façon dont les humains coordonnent l'accès aux piles. Ils pourraient simplement utiliser suppression aléatoire comme les cartes réseau le font physiquement pour déterminer quelle carte peut accéder exclusivement au fil réseau. Si cela fonctionne pour NIC , cela devrait également fonctionner pour les humains.
  2. Il évolue presque indéfiniment si chaque travailleur a son propre ensemble de piles. Les travailleurs peuvent ensuite prendre de gros morceaux de chaussettes dans le panier d’entrée (très peu de conflits, car ils le font rarement) et ils n’ont pas besoin de se synchroniser lors de la distribution des chaussettes (car ils ont des piles de fils locaux). À la fin, tous les travailleurs doivent syndiquer leurs ensembles de piles. Je crois que cela peut être fait en O (journal (nombre de travailleurs * piles par travailleur)) si les travailleurs forment un arbre d'agrégation.

Qu'en est-il du problème de distinction d'élément ? Comme le précise l'article, le problème de la distinction des éléments peut être résolu dans O(N). C'est la même chose pour le problème des chaussettes (également O(N), si vous n'avez besoin que d'une étape de distribution (j'ai proposé plusieurs étapes uniquement parce que les humains calculent mal - une étape suffit si vous distribuez sur md5(color, length, pattern, ...), c'est-à-dire un hash parfait ​​de tous les attributs)).

Clairement, on ne peut pas aller plus vite que O(N), on a donc atteint le borne inférieure optimale.

Bien que les sorties ne soient pas exactement les mêmes (dans un cas, il s’agit d’un booléen. Dans l’autre cas, les paires de chaussettes), les complexités asymptotiques sont les mêmes.

2392
usr

Comme l'architecture du cerveau humain est complètement différente de celle d'un processeur moderne, cette question n'a aucun sens pratique.

Les humains peuvent conquérir les algorithmes de la CPU en utilisant le fait que "trouver une paire correspondante" peut être une opération pour un ensemble pas trop gros.

Mon algorithme:

spread_all_socks_on_flat_surface();
while (socks_left_on_a_surface()) {
     // Thanks to human visual SIMD, this is one, quick operation.
     pair = notice_any_matching_pair();
     remove_socks_pair_from_surface(pair);
}

Au moins, c’est ce que j’utilise dans la vie réelle et je le trouve très efficace. L'inconvénient est qu'il nécessite une surface plane, mais elle est généralement abondante.

564
dpc.pw

Cas 1 : Toutes les chaussettes sont identiques (c'est d'ailleurs ce que je fais dans la vie réelle).

Choisissez-en deux pour en faire une paire. Temps constant.

Cas 2 : Il existe un nombre constant de combinaisons (propriété, couleur, taille, texture, etc.).

Utilisez sorte de radix . Ce n'est que temps linéaire, car la comparaison n'est pas nécessaire.

Cas 3 : le nombre de combinaisons n'est pas connu à l'avance (cas général).

Nous devons faire une comparaison pour vérifier si deux chaussettes viennent en paire. Choisissez l'un des algorithmes de tri basés sur la comparaison O(n log n).

Cependant, dans la réalité, lorsque le nombre de chaussettes est relativement petit (constant), ces algorithmes théoriquement optimaux ne fonctionneraient pas bien. Cela pourrait prendre encore plus de temps que la recherche séquentielle, qui nécessite théoriquement un temps quadratique.

250
Terry Li

Réponse non algorithmique, mais "efficace" quand je le fais:

  • étape 1) jetez toutes vos chaussettes existantes

  • étape 2) allez à Walmart et achetez-les par paquets de 10 - n paquets de blanc et m paquets de noir. Pas besoin d'autres couleurs dans la vie quotidienne.

Pourtant, maintes et maintes fois, je dois le refaire (chaussettes égarées, endommagées, etc.), et je n'aime pas jeter trop souvent de très bonnes chaussettes (et j'aurais aimé qu'ils vendent toujours la même référence de chaussettes!). une approche différente.

Réponse algorithmique:

Considérez que si vous ne tirez qu'une chaussette pour la deuxième pile de chaussettes, vos chances de trouver la chaussette correspondante lors d'une recherche naïve sont plutôt faibles.

  • Alors prenez cinq d'entre eux au hasard et mémorisez leur forme ou leur longueur.

Pourquoi cinq? Habituellement, les humains sont bons et se souviennent d’entre cinq et sept éléments différents dans la mémoire de travail - un peu comme l’équivalent humain d’une pile RPN - cinq est une valeur sûre par défaut.

  • Prenez-en un dans la pile de 2n-5.

  • Cherchez maintenant une correspondance (correspondance visuelle de motifs - les humains sont bons avec une petite pile) dans les cinq dessinés, si vous n'en trouvez pas, ajoutez-les à vos cinq.

  • Continuez à choisir des chaussettes au hasard dans la pile et comparez-les à vos chaussettes 5 + 1 pour un match. Au fur et à mesure que votre pile grandira, cela réduira vos performances mais augmentera vos chances. Plus vite.

N'hésitez pas à écrire la formule pour calculer le nombre d'échantillons à prélever pour une probabilité de correspondance de 50%. IIRC c'est une loi hypergéométrique.

Je fais ça tous les matins et j'ai rarement besoin de plus de trois matchs nuls - mais j'ai n paires similaires (environ 10, donner ou prendre celles qui ont été perdues) de m chaussettes blanches en forme. Vous pouvez maintenant estimer la taille de ma pile de stocks :-)

BTW, j’ai trouvé que la somme des coûts de transaction liés au tri de toutes les chaussettes à chaque fois que j’avais besoin d’une paire était bien moindre que de le faire une fois et lier les chaussettes. Un juste-à-temps fonctionne mieux car vous n'avez pas besoin de lier les chaussettes, il y a aussi un rendement marginal décroissant (vous continuez à chercher ces deux ou trois chaussettes qui se trouvent quelque part dans la lessive et dont vous avez besoin finir de faire correspondre vos chaussettes et vous perdez du temps à ce sujet).

154
guylhem

Ce que je fais, c'est que je prenne la première chaussette et la pose (par exemple sur le bord du bol de la lessive). Ensuite, je prends une autre chaussette et vérifie si elle est identique à la première chaussette. Si c'est le cas, je les enlève tous les deux. Si ce n'est pas le cas, je le pose à côté de la première chaussette. Ensuite, je prends la troisième chaussette et la compare aux deux premières (si elles sont toujours là). Etc.

Cette approche peut être assez facilement implémentée dans un tableau, en supposant que "retirer" les chaussettes est une option. En fait, vous n'avez même pas besoin de "retirer" les chaussettes. Si vous n'avez pas besoin de trier les chaussettes (voir ci-dessous), vous pouvez simplement les déplacer et obtenir un tableau contenant toutes les chaussettes disposées par paires dans le tableau.

En supposant que la seule opération pour les chaussettes est de comparer pour l'égalité, cet algorithme est fondamentalement toujours un n2 algorithme, bien que je ne connaisse pas le cas moyen (jamais appris à calculer cela).

Le tri améliore évidemment l'efficacité, en particulier dans la vie réelle, où vous pouvez facilement "insérer" une chaussette entre deux autres chaussettes. En calculant la même chose pourrait être réalisé par un arbre, mais c'est un espace supplémentaire. Et, bien sûr, nous sommes revenus à NlogN (ou un peu plus, s'il y a plusieurs chaussettes qui sont identiques en fonction des critères de tri, mais pas de la même paire).

En dehors de cela, je ne peux penser à rien, mais cette méthode semble être assez efficace dans la vie réelle. :)

102
Vilx-

C'est poser la mauvaise question. La bonne question à poser est la suivante: pourquoi est-ce que je passe du temps à trier les chaussettes? Combien cela coûte-t-il sur une base annuelle, lorsque vous valorisez votre temps libre pour X unités monétaires de votre choix?

Et plus souvent qu'autrement, ce n'est pas seulement aucun temps libre, c'est matin temps libre, que vous pourriez passer au lit, ou siroter votre café, ou partir un peu plus tôt et ne pas être pris dans la circulation.

Il est souvent bon de prendre du recul et de réfléchir au problème.

Et il y a un moyen!

Trouvez une chaussette que vous aimez. Tenez compte de toutes les caractéristiques pertinentes: couleur dans différentes conditions d'éclairage, qualité et durabilité globales, confort dans différentes conditions climatiques et absorption des odeurs. Il est également important qu'ils ne perdent pas leur élasticité lors du stockage, de sorte que les tissus naturels sont bons et qu'ils devraient être disponibles dans un emballage plastique.

C'est mieux s'il n'y a pas de différence entre les chaussettes gauche et droite, mais ce n'est pas critique. Si les chaussettes sont symétriques gauche-droite, trouver une paire est une opération O(1) et trier les chaussettes est une opération approximative O(M), où M est le nombre de places dans votre maison, vous avez jonché de chaussettes, idéalement un petit nombre constant.

Si vous avez choisi une paire de fantaisie avec une chaussette gauche et une chaussette différentes, effectuez un tri complet avec les godets des pieds droit et gauche et prenez O (N + M), où N est le nombre de chaussettes et M est identique à ci-dessus. Quelqu'un d'autre peut donner la formule pour les itérations moyennes de trouver la première paire, mais le cas le plus défavorable pour trouver une paire avec une recherche à l'aveugle est N/2 + 1, ce qui devient un cas astronomique pour un nombre de N raisonnable. Cela peut être accéléré avec une image avancée algorithmes de reconnaissance et heuristiques, lors du balayage de la pile de chaussettes non triées avec Mk1 Eyeball .

Ainsi, un algorithme permettant d’atteindre l’efficacité de l’appariement de chaussettes O(1) (en supposant une chaussette symétrique) est le suivant:

  1. Vous devez estimer le nombre de paires de chaussettes dont vous aurez besoin pour le reste de votre vie, ou peut-être jusqu'à ce que vous preniez votre retraite et que vous passiez à des climats plus chauds, sans avoir à porter de chaussettes plus jamais. Si vous êtes jeune, vous pouvez également estimer le temps qu'il faudra avant que nous ayons tous des robots pour trier les chaussettes chez nous, et le problème dans son ensemble deviendra inutile.

  2. Vous devez savoir comment commander votre chaussette sélectionnée en vrac, combien cela coûte et comment elle est livrée.

  3. Commandez les chaussettes!

  4. Débarrassez-vous de vos vieilles chaussettes.

Une étape 3 alternative consisterait à comparer les coûts d’achat d’un même montant de chaussettes peut-être moins chères, quelques paires à la fois, au fil des années, et à ajouter le coût du tri des chaussettes, mais croyez-moi, l’achat en vrac coûte moins cher! En outre, la valeur des chaussettes stockées augmente au même rythme que l’inflation du prix des actions, ce qui est supérieur à ce que vous obtiendriez avec de nombreux investissements. Là encore, il y a aussi un coût de stockage, mais les chaussettes ne prennent vraiment pas beaucoup de place sur l'étagère supérieure d'un placard.

Problème résolu. Donc, procurez-vous simplement de nouvelles chaussettes, jetez/donnez vos anciennes chaussettes et vivez heureux pour toujours après avoir su que vous économisiez de l'argent et du temps tous les jours pour le reste de votre vie.

58
hyde

La limite théorique est O(n) car vous devez toucher chaque chaussette (à moins que certaines ne soient déjà associées d'une manière ou d'une autre).

Vous pouvez obtenir O(n) avec sorte de base . Il vous suffit de choisir des attributs pour les compartiments.

  1. D'abord, vous pouvez choisir (le sien, le mien) - séparez-les en 2 piles,
  2. utilisez ensuite des couleurs (vous pouvez choisir n'importe quel ordre de couleurs, par exemple, alphabétiquement, par nom de couleur) - séparez-les en piles par couleur (n'oubliez pas de conserver l'ordre initial de l'étape 1 pour toutes les chaussettes de la même pile),
  3. puis longueur de la chaussette,
  4. puis texture, ....

Si vous pouvez choisir un nombre limité d'attributs, mais suffisamment d'attributs pouvant identifier chaque paire de manière unique, vous devez le faire en O (k * n), qui est O(n) si nous pouvons considérer que k est limité.

49
andredor

En solution pratique:

  1. Faire rapidement des piles de chaussettes faciles à distinguer. (Dis par couleur)
  2. Tri rapide chaque pile et utilise la longueur de la chaussette pour la comparaison. En tant qu'être humain, vous pouvez décider assez rapidement de la chaussette à utiliser pour cloisonner et éviter le pire des cas. (Vous pouvez voir plusieurs chaussettes en parallèle, utilisez-le à votre avantage!)
  3. Arrêtez de trier les piles lorsqu'elles atteignent un seuil permettant de trouver instantanément des paires de paires et des chaussettes impaires

Si vous avez 1000 chaussettes, avec 8 couleurs et une distribution moyenne, vous pouvez faire 4 piles de 125 chaussettes toutes les 125 secondes. Avec un seuil de 5 chaussettes, vous pouvez trier chaque pile en 6 fois. (Compter 2 secondes pour jeter une chaussette sur la pile droite ne vous prendra que moins de 4 heures.)

Si vous ne disposez que de 60 chaussettes, de 3 couleurs et de 2 sortes de chaussettes (la vôtre/celle de votre femme), vous pouvez trier chaque pile de 10 chaussettes en 1 fois (seuil = 5). (En comptant 2 secondes, cela vous prendra 2 minutes).

Le tri par compartiments initial accélérera votre processus car il divisera vos n chaussettes en k compartiments en c*n temps, de sorte que vous ne ferez que du travail c*n*log(k). (Sans tenir compte du seuil). En résumé, vous travaillez sur n*c*(1 + log(k)), où c est le moment de jeter une chaussette sur une pile.

Cette approche sera favorable par rapport à n'importe quelle méthode c*x*n + O(1) à peu près aussi longtemps que log(k) < x - 1.


En informatique, cela peut être utile: nous avons une collection de n choses, un ordre sur celles-ci (longueur) ainsi qu'une relation d'équivalence (informations supplémentaires, par exemple la couleur des chaussettes). La relation d'équivalence nous permet de créer une partition de la collection d'origine et, dans chaque classe d'équivalence, notre ordre est toujours conservé. Le mappage d'un chose vers sa classe d'équivalence peut être effectué en O (1), de sorte que seul O(n) est nécessaire pour affecter chaque élément à une classe. Maintenant, nous avons utilisé nos informations supplémentaires et pouvons procéder de n'importe quelle manière pour trier chaque classe. L'avantage est que les ensembles de données sont déjà nettement plus petits.

La méthode peut également être imbriquée, si nous avons plusieurs relations d’équivalence -> créer des piles de couleurs, que dans chaque partition de pile sur une texture, que trier par longueur. Toute relation d'équivalence qui crée une partition avec plus de 2 éléments de taille identique apportera une amélioration de la vitesse par rapport au tri (à condition que nous puissions affecter directement une chaussette à sa pile), et le tri peut avoir lieu très rapidement sur des ensembles de données plus petits.

31
Samuel

Vous essayez de résoudre le mauvais problème.

Solution 1: Chaque fois que vous mettez des chaussettes sales dans votre panier à linge, nouez-les en un petit noeud. De cette façon, vous ne ferez aucun tri après le lavage. Pensez-y comme si vous enregistriez un index dans une base de données Mongo. Un peu de travail à venir pour des économies d’ordinateur par la suite.

Solution 2: Si c'est l'hiver, vous n'avez pas besoin de porter des chaussettes assorties. Nous sommes des programmeurs. Personne n'a besoin de savoir, tant que cela fonctionne.

Solution 3: Répartissez le travail. Vous souhaitez exécuter un processus CPU aussi complexe de manière asynchrone, sans bloquer l'interface utilisateur. Prenez cette pile de chaussettes et mettez-les dans un sac. Ne cherchez une paire que lorsque vous en avez besoin. De cette façon, la quantité de travail nécessaire est beaucoup moins perceptible.

J'espère que cela t'aides!

26
Nikolay Dyankov

Cette question est en réalité profondément philosophique. Au fond, il s’agit de savoir si le pouvoir des gens de résoudre des problèmes (le "poids" de notre cerveau) équivaut à ce que l’on peut réaliser avec des algorithmes.

Un algorithme évident pour le tri des chaussettes est le suivant:

Let N be the set of socks that are still unpaired, initially empty
for each sock s taken from the dryer
  if s matches a sock t in N
    remove t from N, bundle s and t together, and throw them in the basket
  else
    add s to N

Maintenant, l'informatique dans ce problème est tout au sujet des étapes

  1. "si s paires avec une chaussette t dans N". Combien de temps pouvons-nous "nous souvenir" de ce que nous avons vu jusqu'à présent?
  2. "retirer t de N" et "ajouter s à N". Combien coûte de garder trace de ce que nous avons vu jusqu'à présent?

Les êtres humains utiliseront diverses stratégies pour y parvenir. La mémoire humaine est associative , quelque chose qui ressemble à une table de hachage où les ensembles de caractéristiques de valeurs stockées sont associés aux valeurs correspondantes elles-mêmes. Par exemple, le concept de "voiture rouge" correspond à toutes les voitures rouges qu'une personne est capable de mémoriser. Quelqu'un avec une mémoire parfaite a une cartographie parfaite. La plupart des gens sont imparfaits à cet égard (et la plupart des autres). La carte associative a une capacité limitée. Les mappages peuvent disparaître dans diverses circonstances (une bière de trop), être enregistrés par erreur ("Je m'appelais bien Betty, pas Nettie" ), ou ne jamais être écrasé même si nous observons que la vérité a changé ("la voiture de papa" évoque "Firebird orange" alors que nous savions qu’il avait échangé cela contre la Camaro rouge).

Dans le cas de chaussettes, rappel parfait signifie regarder une chaussette s produit toujours la mémoire de son frère t, y compris suffisamment d'informations (où il est sur la planche à repasser) pour localiser t en temps constant. Une personne avec une mémoire photographique accomplit les deux 1 et 2 en temps constant sans échec.

Une personne dont la mémoire est moins parfaite pourrait utiliser quelques classes d'équivalence de bon sens basées sur des fonctionnalités qu'il est capable de suivre: taille (papa, maman, bébé), couleur (verdâtre, rougeâtre, etc.), motif (argyle, simple, etc.). , style (foot, genou, etc.). Ainsi, la planche à repasser serait divisée en sections pour les catégories. Cela permet généralement de localiser la catégorie en temps constant par mémoire, mais une recherche linéaire dans la catégorie "compartiment" est alors nécessaire.

Quelqu'un qui n'a ni mémoire ni imagination (désolé) gardera simplement les chaussettes dans une pile et effectuera une recherche linéaire de toute la pile.

Un maniaque pourrait utiliser des étiquettes numériques pour les paires, comme suggéré par quelqu'un. Cela ouvre la porte à un ordre total, ce qui permet à l'homme d'utiliser exactement les mêmes algorithmes que ceux utilisés avec un processeur: recherche binaire, arbres, hachages, etc.

Donc, le "meilleur" algorithme dépend des qualités du wetware/du matériel/du logiciel qui l’exécute et de notre volonté de "tricher" en imposant un ordre total aux paires. Certes, un "meilleur" méta algorithme consiste à embaucher le meilleur trieur de chaussettes au monde: une personne ou une machine capable d'acquérir et de stocker rapidement un jeu énorme N of sock attribute des ensembles dans une mémoire associative 1-1 avec une recherche, une insertion et une suppression constantes dans le temps. Des personnes et des machines comme celle-ci peuvent être achetées. Si vous en avez un, vous pouvez associer toutes les chaussettes en O(N) pour N paires, ce qui est optimal. Les étiquettes de commande totales vous permettent d’utiliser le hachage standard pour obtenir le même résultat avec un ordinateur humain ou matériel.

25
Gene

Coût: chaussettes de déménagement -> hautes, chaussettes de recherche/recherche en ligne -> petites

Ce que nous voulons, c'est réduire le nombre de déménagements et compenser par le nombre de recherches. En outre, nous pouvons utiliser l'environnement multithréé de l'Homo Sapiens pour stocker davantage d'éléments dans le cache de descision.

X = Vôtre, Y = Vos conjoints

De la pile A de toutes les chaussettes:

Choisissez deux chaussettes, placez la chaussette X correspondante dans la ligne X et la chaussette Y dans la ligne Y à la position disponible suivante.

Faites jusqu'à ce que A soit vide.

Pour chaque ligne X et Y

  1. Choisissez la première chaussette en ligne, cherchez le long de la ligne jusqu'à trouver la chaussette correspondante.

  2. Mettez dans la ligne de chaussettes finie correspondante.

  3. Facultatif Lorsque vous recherchez la ligne et que la chaussette que vous regardez est identique à la précédente, effectuez l'étape 2 pour ces chaussettes.

Vous pouvez éventuellement choisir deux chaussettes sur cette ligne au lieu de deux, car la mémoire cache est suffisamment grande pour nous permettre d'identifier rapidement si l'une des chaussettes correspond à la chaussette actuelle de la ligne que vous observez. Si vous avez la chance d'avoir trois bras, vous pouvez éventuellement analyser trois chaussettes en même temps, étant donné que la mémoire du sujet est suffisamment grande.

Faites jusqu'à ce que X et Y soient vides.

Terminé

Cependant, comme cela a une complexité similaire à celle des sélections, le temps nécessaire est bien moindre en raison des vitesses d’entrée/sortie (chaussettes mobiles) et de recherche (recherche de chaussettes dans la ligne).

20
1-----1

Voici une limite inférieure Omega (n log n) dans le modèle basé sur la comparaison. (La seule opération valide consiste à comparer deux chaussettes.)

Supposons que vous sachiez que vos 2n chaussettes sont disposées de la manière suivante:

p1 p2 p3 ... pn pf(1) pf(2) ... pf(n)

où f est une permutation inconnue de l'ensemble {1,2, ..., n}. Sachant cela ne peut pas rendre le problème plus difficile. Il y en a! sorties possibles (appariements entre première et deuxième moitié), ce qui signifie que vous avez besoin de comparaisons log (n!) = Omega (n log n). Ceci peut être obtenu en triant.

Puisque vous vous intéressez aux problèmes liés à la distinction des éléments: il est plus difficile de prouver que Omega (n log n) est lié à la distinction des éléments, car la sortie est binaire oui/non. Ici, la sortie doit être une correspondance et le nombre de sorties possibles suffit pour obtenir une limite décente. Cependant, il existe une variante liée à la distinction d'éléments. Supposons que vous receviez 2n chaussettes et demandez-vous si elles peuvent être jumelées de manière unique. Vous pouvez obtenir une réduction de ED en envoyant (un1, une2, ..., unen) à (un1, une1, une2, une2, ..., unen, unen). (Entre parenthèses, la preuve de la dureté de l'ED est très intéressante, via la topologie .)

Je pense qu’il devrait y avoir un Omega (n2) lié au problème initial si vous autorisez uniquement les tests d’égalité. Mon intuition est la suivante: considérons un graphique dans lequel vous ajoutez un Edge après un test et expliquez que si le graphique n'est pas dense, la sortie n'est pas déterminée de manière unique.

20
sdcvvc

Voici comment je le fais réellement, pour p paires de chaussettes (n = 2p chaussettes individuelles):

  • Prenez une chaussette au hasard dans la pile.
  • Pour la première chaussette, ou si toutes les chaussettes précédemment choisies ont été appariées, placez simplement la chaussette dans le premier "emplacement" d'un "tableau" de chaussettes non appariées devant vous.
  • Si vous avez sélectionné une ou plusieurs chaussettes non appariées, comparez votre chaussette actuelle à toutes les chaussettes non appariées du tableau.
    • Il est possible de séparer les chaussettes en classes ou types généraux (blanc/noir, cheville/crew, athlétique/robe) lors de la construction de votre tableau, et de "forer" pour comparer uniquement les points similaires.
    • Si vous trouvez une correspondance acceptable, associez les deux chaussettes et supprimez-les du tableau.
    • Si vous ne le faites pas, placez la chaussette actuelle dans le premier emplacement libre de la matrice.
  • Répétez avec chaque chaussette.

Le pire scénario de ce schéma est que chaque paire de chaussettes est suffisamment différente pour pouvoir correspondre exactement et que les premières n/2 que vous choisissez sont toutes différentes. Ceci est votre O (n2), et c’est extrêmement peu probable. Si le nombre de types de chaussettes uniques t est inférieur au nombre de paires p = n/2, et que les chaussettes de chaque type se ressemblent suffisamment (généralement en cas d'usure). termes associés) que toute chaussette de ce type peut être jumelée à une autre, puis, comme je l’ai inféré plus haut, le nombre maximal de chaussettes que vous aurez à comparer est t, après quoi le prochain pull will correspond à l'une des chaussettes non appariées. Ce scénario est beaucoup plus probable dans le tiroir à chaussettes moyen que dans le pire des cas et réduit la complexité du pire des cas à O (n * t) où habituellement t << n.

18
KeithS

Approche du monde réel:

Le plus rapidement possible, retirez les chaussettes de la pile non triée une par une et placez-les en piles devant vous. Les piles doivent être disposées de manière relativement peu encombrante, avec toutes les chaussettes orientées dans la même direction; le nombre de piles est limité par la distance que vous pouvez facilement atteindre. Le choix d’une pile sur laquelle mettre une chaussette doit être effectué - le plus rapidement possible - en la plaçant sur une pile de chaussettes apparemment semblables; les erreurs occasionnelles de type I (mettre une chaussette sur une pile à laquelle elle n'appartient pas) ou de type II (mettre une chaussette dans sa propre pile lorsqu'il existe une pile de chaussettes semblables) peuvent être tolérées - la considération la plus importante est: vitesse. Une fois que toutes les chaussettes sont empilées, parcourez rapidement les piles de chaussettes multiples en créant et en retirant les paires (elles se dirigent vers le tiroir). S'il y a des chaussettes non assorties dans la pile, réempilez-les au mieux (dans la limite la plus rapide possible). Lorsque toutes les piles de chaussettes multiples ont été traitées, faites correspondre les chaussettes appariées restantes qui n'ont pas été appariées en raison d'erreurs de type II. Whoosh, vous avez terminé - et j'ai beaucoup de chaussettes et je ne les lave pas avant qu'une grande partie ne soit sale. Autre remarque pratique: je fais glisser le haut d’une des chaussettes par-dessus l’autre, tirant parti de leurs propriétés élastiques, afin qu’elles restent ensemble pendant le transport dans le tiroir et dans le tiroir.

16
Jim Balter

D'après votre question, il est clair que vous n'avez pas beaucoup d'expérience réelle avec la lessive :). Vous avez besoin d'un algorithme qui fonctionne bien avec un petit nombre de chaussettes non appariables.

Les réponses apportées jusqu'à présent ne font pas bon usage de nos capacités de reconnaissance des modèles humains. Le jeu de Set indique comment bien le faire: placez toutes les chaussettes dans un espace à deux dimensions pour pouvoir les reconnaître et les atteindre facilement avec vos mains. Cela vous limite à une superficie d’environ 120 * 80 cm. À partir de là, sélectionnez les paires que vous reconnaissez et supprimez-les. Mettez des chaussettes supplémentaires dans l'espace libre et répétez l'opération. Si vous lavez pour des personnes avec des chaussettes facilement reconnaissables (les petits enfants viennent à l’esprit), vous pouvez faire un tri à base en sélectionnant ces chaussettes d’abord. Cet algorithme ne fonctionne bien que lorsque le nombre de chaussettes simples est faible

14
Stephan Eggermont

Prenez une première chaussette et placez-la sur une table. Maintenant, choisissez une autre chaussette; si elle correspond à la première cueillie, placez-la sur la première. Sinon, placez-le sur la table à une petite distance de la première. Choisissez une troisième chaussette; si elle correspond à l'une des deux précédentes, placez-la sur celles-ci ou placez-la à une petite distance de la troisième. Répétez l'opération jusqu'à ce que vous ayez ramassé toutes les chaussettes.

14
Justin Fay

Afin de dire à quel point il est efficace de coupler des chaussettes à partir d’une pile, nous devons d’abord définir la machine, car l’appariement n’est effectué ni par une machine ni par une machine à accès aléatoire, qui servent normalement de base à une analyse algorithmique.

La machine

La machine est une abstraction d'un élément du monde réel appelé être humain. Il est capable de lire dans l'environnement via une paire d'yeux. Et notre modèle de machine est capable de manipuler l'environnement en utilisant 2 bras. Les opérations logiques et arithmétiques sont calculées en utilisant notre cerveau (heureusement ;-)).

Nous devons également prendre en compte le temps d'exécution intrinsèque des opérations atomiques pouvant être effectuées avec ces instruments. En raison de contraintes physiques, les opérations effectuées avec un bras ou un œil ont une complexité temporelle non constante. En effet, nous ne pouvons pas déplacer un tas de chaussettes sans fin avec un bras ni un œil pour voir le bas de la chaussette sur un tas de chaussettes sans fin.

Cependant, la physique mécanique nous offre également quelques avantages. Nous ne sommes pas limités à bouger au plus une chaussette avec un bras. Nous pouvons en déplacer plusieurs à la fois.

Donc, en fonction de l'analyse précédente, les opérations suivantes doivent être utilisées dans l'ordre décroissant:

  • opérations logiques et arithmétiques
  • lectures environnementales
  • modifications de l'environnement

Nous pouvons également utiliser le fait que les gens ne disposent que d'une quantité très limitée de chaussettes. Ainsi, une modification de l'environnement peut impliquer toutes les chaussettes de la pile.

L'algorithme

Alors voici ma suggestion:

  1. Étalez toutes les chaussettes dans la pile sur le sol.
  2. Trouvez une paire en regardant les chaussettes sur le sol.
  3. Répétez à partir de 2 jusqu'à ce qu'aucune paire ne puisse être faite.
  4. Répétez à partir de 1 jusqu'à ce qu'il n'y ait pas de chaussettes sur le sol.

L'opération 4 est nécessaire car, lors de l'épandage de chaussettes sur le sol, certaines chaussettes peuvent en cacher d'autres. Voici l'analyse de l'algorithme:

L'analyse

L'algorithme se termine avec une probabilité élevée. Cela est dû au fait qu’il est impossible de trouver des paires de chaussettes à l’étape 2.

Pour l'analyse suivante de l'association des paires n, nous supposons qu'au moins la moitié des chaussettes _2n_ ne sont pas masquées après l'étape 1. Nous pouvons donc trouver _n/2_ paires. Cela signifie que la boucle correspond à l'étape 4 et qu'elle est exécutée O(log n) fois. L'étape 2 est exécutée O(n^2) fois. Nous pouvons donc conclure:

  • L'algorithme implique O(ln n + n) modifications de l'environnement (étape 1 O(ln n) ainsi que le prélèvement de chaque paire de chaussettes sur le sol)
  • L'algorithme implique O(n^2) lecture environnementale à partir de l'étape 2
  • L'algorithme implique O(n^2) opérations logiques et arithmétiques pour comparer une chaussette à une autre à l'étape 2

Nous avons donc une complexité d'exécution totale de O(r*n^2 + w*(ln n + n))r et w sont les facteurs des opérations de lecture et d'écriture environnementales pour une quantité raisonnable de chaussettes. Le coût des opérations logiques et arithmétiques est omis, car nous supposons qu'il faut un nombre constant d'opérations logiques et arithmétiques pour décider si 2 chaussettes appartiennent à la même paire. Cela peut ne pas être réalisable dans tous les scénarios.

12
SpaceTrucker

J'ai proposé une autre solution qui ne promettrait pas moins d'opérations, ni moins de consommation de temps, mais il faudrait essayer de voir si elle peut constituer une heuristique suffisamment bonne pour réduire la consommation de temps dans les énormes séries de paires de chaussettes.

Préconditions: Rien ne garantit qu'il existe les mêmes chaussettes. S'ils sont de la même couleur, cela ne signifie pas qu'ils ont la même taille ou le même motif. Les chaussettes sont mélangées au hasard. Il peut y avoir un nombre impair de chaussettes (il en manque, nous ne savons pas combien). Préparez-vous à mémoriser une variable "index" et définissez-la sur 0.

Le résultat aura une ou deux piles: 1. "apparié" et 2. "manquant"

Heuristique:

  1. Trouvez la chaussette la plus distinctive.
  2. Trouvez sa correspondance.
  3. S'il n'y a pas de correspondance, placez-le sur la pile "manquante".
  4. Répétez de 1. jusqu'à ce qu'il n'y ait plus de chaussettes plus distinctives.
  5. S'il y a moins de 6 chaussettes, aller à 11.
  6. Paire à l'aveugle toutes les chaussettes à son voisin (ne pas l'emballer)
  7. Trouvez toutes les paires appariées, emballez-la et déplacez les paires emballées vers une pile "appariée"; S'il n'y a pas eu de nouvelle correspondance - incrémenter "index" de 1
  8. Si "index" est supérieur à 2 (la valeur peut dépendre du nombre de chaussettes car avec un plus grand nombre de chaussettes, les chances de les appairer à l'aveuglette sont réduites), passez à 11
  9. Mélangez le reste
  10. Aller à 1
  11. Oubliez "index"
  12. Choisir une chaussette
  13. Trouver sa paire
  14. S'il n'y a pas de paire pour la chaussette, déplacez-la vers la pile "manquante"
  15. Si la correspondance est trouvée, associez-la et placez-la dans la pile "correspondante"
  16. S'il y a encore plus d'une chaussette, passez à 12
  17. S'il n'en reste qu'un, passez à 14
  18. Sourire satisfait :)

En outre, il pourrait être ajouté vérifier pour les chaussettes endommagées aussi, comme si l'enlèvement de ceux-ci. Il pourrait être inséré entre 2 et 3 et entre 13 et 14.

J'ai hâte de connaître vos expériences ou vos corrections.

12
Sasa
List<Sock> UnSearchedSocks = getAllSocks();
List<Sock> UnMatchedSocks = new list<Sock>();
List<PairOfSocks> PairedSocks = new list<PairOfSocks>();

foreach (Sock newSock in UnsearchedSocks)
{
  Sock MatchedSock = null;
  foreach(Sock UnmatchedSock in UnmatchedSocks)
  {
    if (UnmatchedSock.isPairOf(newSock))
    {
      MatchedSock = UnmatchedSock;
      break;
    }
  }
  if (MatchedSock != null)
  {
    UnmatchedSocks.remove(MatchedSock);
    PairedSocks.Add(new PairOfSocks(MatchedSock, NewSock));
  }
  else
  {
    UnmatchedSocks.Add(NewSock);
  }
}
12
Chad

Lorsque je trie des chaussettes, je fais une approximation de sorte de base , en laissant tomber des chaussettes près d'autres chaussettes du même type de couleur/motif. Sauf dans le cas où je peux voir une correspondance exacte à/près de l'endroit où je suis sur le point de déposer la chaussette, j'extrais la paire à ce moment-là.

Presque tous les autres algorithmes (y compris la réponse la mieux notée par usr ) trient puis suppriment les paires. Je trouve qu'en tant qu'être humain, il est préférable de minimiser le nombre de chaussettes considérées à la fois.

Je le fais par:

  1. Choisir une chaussette distinctive (tout ce qui attire mon attention dans la pile).
  2. Commencez un tri de base à partir de cet emplacement conceptuel en tirant les chaussettes de la pile en vous basant sur la similitude avec celle-ci.
  3. Placez la nouvelle chaussette près de la pile actuelle, avec une distance en fonction de sa différence. Si vous vous trouvez en train de mettre la chaussette l'une sur l'autre parce qu'elle est identique, formez-la et retirez-la. Cela signifie que les comparaisons futures nécessitent moins d’efforts pour trouver le bon endroit.

Cela tire parti de la capacité humaine à faire une correspondance approximative dans le temps [O(1)], ce qui est quelque peu équivalent à l'établissement d'une carte de hachage sur un dispositif informatique.

En tirant d'abord sur les chaussettes distinctives, vous laissez un espace pour "zoomer" sur les caractéristiques moins distinctives, pour commencer.

Après avoir éliminé les couleurs fluro, les chaussettes à rayures et les trois paires de chaussettes longues, vous pourriez vous retrouver avec des chaussettes essentiellement blanches, triées en fonction de leur état d'usure.

À un moment donné, les différences entre les chaussettes sont suffisamment minimes pour que personne ne les remarque, et aucun effort supplémentaire n'est nécessaire.

11
Andrew Hill

Chaque fois que vous prenez une chaussette, mettez-la au même endroit. Ensuite, la prochaine chaussette que vous prenez, si elle ne correspond pas à la première chaussette, placez-la à côté de la première. Si c'est le cas, il y a une paire. De cette façon, le nombre de combinaisons importées n'a pas vraiment d'importance et il n'y a que deux possibilités pour chaque chaussette que vous ramassez - soit une correspondance existe déjà dans votre gamme de chaussettes, soit ce n'est pas le cas, ce qui signifie que vous ajoutez-le à une place dans le tableau.

Cela signifie également que vous n'aurez probablement jamais toutes vos chaussettes dans le tableau, car les chaussettes seront retirées à mesure qu'elles sont appariées.

10
trpt4him

Les chaussettes, qu'elles soient réelles ou à structure de données analogue, seraient fournies par paires.

La réponse la plus simple est avant de permettre à la paire d'être séparée, une structure de données unique pour la paire aurait dû être initialisée, laquelle contiendrait un pointeur sur la chaussette gauche et droite, permettant ainsi de référencer les chaussettes directement ou via leur paire. Une chaussette peut également être étendue pour contenir un pointeur sur son partenaire.

Cela résout tout problème d'appariement informatique en le supprimant avec une couche d'abstraction.

En appliquant la même idée au problème pratique de l’association de chaussettes, la réponse évidente est la suivante: ne laissez jamais vos chaussettes être non appariées. Les chaussettes sont fournies par paire, placées dans le tiroir sous forme de paire (peut-être en les agglomérant ensemble), portées par paire. Mais le point où le désappariement est possible est dans la laveuse, il suffit donc d'un mécanisme physique qui permette aux chaussettes de rester ensemble et d'être lavées efficacement.

Il y a deux possibilités physiques:

Pour un objet "paire" gardant un pointeur sur chaque chaussette, nous pourrions avoir un sac en tissu que nous utilisons pour garder les chaussettes ensemble. Cela semble être une surcharge massive.

Mais pour que chaque chaussette garde une référence à l'autre, il existe une solution simple: un popper (ou un "bouton-poussoir" si vous êtes américain), tels que:

http://www.aliexpress.com/compare/compare-invisible-snap-buttons.html

Ensuite, tout ce que vous ferez, c’est assembler vos chaussettes juste après les avoir enlevées et les mettre dans votre panier à linge. Là encore, vous avez supprimé le problème de la nécessité de coupler vos chaussettes avec une abstraction physique du concept de "paire".

10
mozboz

Considérons une table de hachage de taille 'N'.

Si nous supposons une distribution normale, alors le nombre estimé d'insertions avec au moins une chaussette mappée sur un seau est NlogN (c'est-à-dire que tous les seaux sont pleins)

J'avais dérivé cela dans le cadre d'un autre casse-tête, mais je serais heureux de pouvoir me tromper. Voici mon article de blog sur le même

Laissons "N" correspondre à une limite supérieure approximative du nombre de couleurs/motifs de chaussettes uniques que vous avez.

Une fois que vous avez une collision (a.k.a: une allumette), retirez simplement cette paire de chaussettes. Répétez la même expérience avec le prochain lot de chaussettes NlogN. La beauté de ceci est que vous pouvez faire des comparaisons parallèles avec NlogN (résolution de collision) en raison du fonctionnement de l'esprit humain. :-)

9
Arvind

J'ai pris des mesures simples pour réduire mon effort en un processus prenant O(1) temps.

En réduisant mes entrées à l'un des deux types de chaussettes (chaussettes blanches pour les loisirs, chaussettes noires pour le travail), il me suffit de déterminer laquelle des deux chaussettes que j'ai en main. (Techniquement, comme ils ne sont jamais lavés ensemble, j'ai réduit le processus à O(0) temps)

Un effort initial est nécessaire pour trouver les chaussettes désirables et pour en acheter en quantité suffisante pour éliminer le besoin de vos chaussettes existantes. Comme je l'avais déjà fait avant mon besoin de chaussettes noires, mon effort était minime, mais le kilométrage peut varier.

Un tel effort initial a été vu à plusieurs reprises dans un code très populaire et efficace. Les exemples incluent # DEFINE'ing pi à plusieurs décimales (d'autres exemples existent, mais c'est celui qui me vient à l'esprit pour le moment).

8
Scott Brickey

J'ai fini d'associer mes chaussettes tout de suite et j'ai trouvé que la meilleure façon de le faire était la suivante:

  • Choisissez l'une des chaussettes et rangez-la (créez un "seau" pour cette paire)
  • Si la suivante est la paire de la précédente, placez-la dans le compartiment existant, sinon créez-en une nouvelle.

Dans le pire des cas, cela signifie que vous aurez n/2 compartiments différents et que vous aurez n-2 déterminations sur le compartiment contenant la paire de chaussettes actuelle. Évidemment, cet algorithme fonctionne bien si vous n'avez que quelques paires. Je l'ai fait avec 12 paires.

Ce n'est pas si scientifique, mais ça marche bien :)

8
maestro

Ma solution ne correspond pas exactement à vos besoins, car elle nécessite officiellement O(n) "extra" space. Cependant, compte tenu de mes conditions, il est très efficace dans mon application pratique. Donc je pense que ça devrait être intéressant.

Combiner avec d'autres tâches

La condition particulière dans mon cas est que je n’utilise pas de sèche-linge, je suspends simplement mes vêtements à un sèche-linge ordinaire. Suspendre des étoffes nécessite des opérations O(n) (d'ailleurs, je considère toujours bin bin problème ici) et le problème, de par sa nature, nécessite un espace "supplémentaire" linéaire. Quand je prends une nouvelle chaussette dans le seau, je vais essayer de la suspendre à côté de sa paire si la paire est déjà suspendue. Si c'est une chaussette d'une nouvelle paire, je laisse un peu d'espace à côté.

Oracle Machine, c'est mieux ;-)

Il faut évidemment un travail supplémentaire pour vérifier si la chaussette correspondante est déjà suspendue quelque part et cela rendrait la solution O(n^2) avec un coefficient de 1/2 pour un ordinateur. Mais dans ce cas, le "facteur humain" est en fait un avantage - je peux habituellement très rapidement (presque O(1)) identifier la chaussette correspondante si elle était déjà accrochée (probablement une cachette imperceptible dans le cerveau est impliquée) - considérez-la comme une sorte de "Oracle" limité comme dans Oracle Machine ;-) Nous, les humains ont ces avantages sur les machines numériques dans certains cas ;-)

Avez-le presque O(n)!

Ainsi, en reliant le problème d’appariement des chaussettes au problème des toiles suspendues, je reçois gratuitement O(n) "espace supplémentaire" et je propose une solution à propos de O(n) dans le temps, qui nécessite juste un peu plus de travail que paire de chaussettes même dans un très mauvais lundi matin ... ;-)

8
wrzasa

Si l'opération "déménagement" est assez coûteuse et que l'opération "comparaison" est peu coûteuse, et vous devez quand même déplacer l'ensemble dans une mémoire tampon où la recherche est beaucoup plus rapide que dans le stockage d'origine ... intégrez simplement le tri dans l'obligation bouge toi.

J'ai trouvé que l'intégration du processus de tri en suspension pour sécher en faisait un jeu d'enfant. Quoi qu'il en soit, je dois ramasser chaque chaussette et la suspendre (mouvement). Cela ne me coûte rien de la suspendre à un endroit précis sur les cordes. Maintenant, juste pour ne pas forcer la recherche de tout le tampon (les cordes), je choisis de placer les chaussettes par couleur/ombre. Plus sombre à gauche, plus clair à droite, plus coloré sur le devant, etc. Maintenant, avant de suspendre chaque chaussette, je cherche à sa droite si celle-ci est déjà assortie, ce qui limite le "balayage" à 2-3 autres chaussettes - et si c'est le cas , J'accroche l'autre juste à côté. Ensuite, je les roule en paires tout en les retirant des cordes une fois sèches.

Maintenant, cela ne semble pas si différent de "former des piles par couleur" suggéré par les réponses principales, mais d’abord, en ne choisissant pas des piles discrètes mais des plages, je n’ai aucun problème à classer si "violet" va à "rouge" ou "bleu"; ça va juste entre. Et ensuite, en intégrant deux opérations (suspendre pour sécher et trier), les frais généraux liés au tri en suspension représentent environ 10% de ce que serait un tri séparé.

8
SF.

J'espère pouvoir apporter quelque chose de nouveau à ce problème. J'ai remarqué que toutes les réponses négligent le fait qu'il existe deux points où vous pouvez effectuer un prétraitement sans ralentir les performances globales de votre blanchisserie.

En outre, nous n’avons pas besoin de supposer un grand nombre de chaussettes, même pour les familles nombreuses. Les chaussettes sont sorties du tiroir et sont portées, puis elles sont jetées dans un endroit (peut-être une corbeille) où elles restent avant d'être lavées. Bien que je n'appellerais pas dit bin une pile LIFO, je dirais qu'il est prudent de supposer que

  1. les gens jettent leurs deux chaussettes à peu près dans la même zone de la corbeille,
  2. la poubelle n'est pas randomisée à aucun moment, et donc
  3. tout sous-ensemble pris dans le haut de cette corbeille contient généralement les deux chaussettes d'une paire.

Étant donné que toutes les machines à laver que je connais sont de taille limitée (quel que soit le nombre de chaussettes à laver), et que la randomisation a lieu dans la machine à laver, quel que soit le nombre de chaussettes dont nous disposons, nous avons toujours de petits sous-ensembles qui ne contiennent presque singletons.

Nos deux étapes de prétraitement consistent à "mettre les chaussettes sur la corde à linge" et "à retirer les chaussettes de la corde à linge", ce que nous devons faire pour obtenir des chaussettes non seulement propres, mais également sèches. Comme pour les machines à laver, les cordes à linge sont finies, et je suppose que nous avons toute la partie de la ligne où nous mettons nos chaussettes en vue.

Voici l'algorithme pour put_socks_on_line ():

while (socks left in basket) {
 take_sock();
 if (cluster of similar socks is present) { 
   Add sock to cluster (if possible, next to the matching pair)
 } else {
  Hang it somewhere on the line, this is now a new cluster of similar-looking socks.      
  Leave enough space around this sock to add other socks later on 
 }
}

Ne perdez pas votre temps à déplacer des chaussettes ou à chercher le meilleur match, tout cela devrait être fait en O (n), ce dont nous aurions également besoin pour les mettre sur la ligne non triées. Les chaussettes ne sont pas encore associées, nous avons seulement plusieurs groupes de similarité sur la ligne. Il est utile que nous ayons un nombre limité de chaussettes ici, car cela nous aide à créer de "bons" clusters (par exemple, s'il n'y a que des chaussettes noires dans l'ensemble de chaussettes, le groupement par couleurs ne serait pas la solution.)

Voici l'algorithme pour take_socks_from_line ():

while(socks left on line) {
 take_next_sock();
 if (matching pair visible on line or in basket) {
   Take it as well, pair 'em and put 'em away
 } else {
   put the sock in the basket
 }

Je tiens à souligner que pour améliorer la vitesse des étapes restantes, il est sage de ne pas choisir au hasard la chaussette suivante, mais de prendre séquentiellement chaussette après chaussette dans chaque groupe. Les deux étapes de prétraitement ne prennent pas plus de temps que de simplement mettre les chaussettes sur la ligne ou dans le panier, ce que nous devons faire quoi qu'il en soit, cela devrait donc grandement améliorer les performances de la blanchisserie.

Après cela, il est facile de faire l’algorithme de partitionnement de hachage. Habituellement, environ 75% des chaussettes sont déjà appariées, ce qui me laisse un très petit sous-ensemble de chaussettes, et ce sous-ensemble est déjà (quelque peu) en cluster (je n'introduis pas beaucoup d'entropie dans mon panier après les étapes de prétraitement). Une autre chose est que les grappes restantes ont tendance à être suffisamment petites pour pouvoir être manipulées en une fois. Il est donc possible de sortir toute une grappe du panier.

Voici l'algorithme pour sort_remaining_clusters ():

while(clusters present in basket) {
  Take out the cluster and spread it
  Process it immediately
  Leave remaining socks where they are
}

Après cela, il ne reste que quelques chaussettes. C’est là que j’introduis dans le système des chaussettes non encore appariées et que je traite les chaussettes restantes sans algorithme particulier - les chaussettes restantes sont très peu nombreuses et peuvent être traitées visuellement très rapidement.

Pour toutes les chaussettes restantes, je suppose que leurs homologues ne sont pas encore lavés et les rangez pour la prochaine itération. Si vous enregistrez une croissance de chaussettes non appariées au fil du temps (une "fuite de chaussette"), vous devriez vérifier votre poubelle - elle pourrait être randomisée (avez-vous des chats qui y dorment?)

Je sais que ces algorithmes reposent sur de nombreuses hypothèses: une corbeille qui agit comme une sorte de pile LIFO, une machine à laver limitée et normale et une corde à linge normale et limitée - mais cela fonctionne toujours avec un très grand nombre de chaussettes .

À propos du parallélisme: tant que vous jetez les deux chaussettes dans le même bac, vous pouvez facilement paralléliser toutes ces étapes.

8
Philipp Flenker

Qu'en est-il de faire un prétraitement? Je coudrais une marque ou un numéro d'identification dans chaque chaussette de manière à ce que chaque paire porte le même numéro de marque/d'identification. Ce processus peut être effectué chaque fois que vous achetez une nouvelle paire de chaussettes. Ensuite, vous pouvez faire un tri de base pour obtenir O(n) coût total. Trouvez une place pour chaque numéro d'identification/marque et choisissez simplement toutes les chaussettes une par une et placez-les au bon endroit.

7
elvitucho

Créez une table de hachage qui sera utilisée pour les chaussettes sans correspondance, en utilisant le motif en tant que hachage. Itérez sur les chaussettes une à une. Si la chaussette a un motif correspondant dans la table de hachage, retirez-la de la table et faites-en une paire. Si la chaussette n'a pas de correspondance, mettez-la dans la table.

7
viper110110

Le problème du tri vos n paires de chaussettes sont O (n). Avant de les jeter dans le linge panier, vous enfilez celui de gauche vers celui de droite. En les retirant, vous coupez le fil et placez chaque paire dans votre tiroir - 2 opérations sur n paires, donc O (n).

Maintenant, la question suivante est simplement de savoir si vous faites votre propre linge et que votre femme fait le sien. C’est un problème probable dans un domaine de problèmes entièrement différent. :)

7
Fred Mitchell

J'y ai pensé très souvent lors de mon doctorat (en informatique). Je suis venu avec plusieurs solutions, en fonction de la capacité de distinguer les chaussettes et ainsi trouver les paires correctes aussi rapidement que possible.

Supposons que le coût de regarder des chaussettes et la mémorisation de leurs motifs distinctifs est négligeable (ε). Ensuite, la meilleure solution consiste simplement à jeter toutes les chaussettes sur une table. Cela implique ces étapes:

  1. Jetez toutes les chaussettes sur une table (1) et créez un hashmap {pattern: position} (ε)
  2. Tant qu'il reste des chaussettes (n/2):
    1. Prenez une chaussette au hasard (1)
    2. Trouver la position de la chaussette correspondante (ε)
    3. Récupérer la chaussette (1) et stocker la paire

C'est en effet la possibilité la plus rapide et elle est exécutée avec une complexité n + 1 = O(n). Mais cela suppose que vous vous souveniez parfaitement de tous les schémas ... En pratique, ce n'est pas le cas, et mon expérience personnelle est que, parfois, vous ne trouvez pas la paire correspondante du premier coup:

  1. Jetez toutes les chaussettes sur une table (1)
  2. Tant qu'il reste des chaussettes (n/2):
    1. Prenez une chaussette au hasard (1)
    2. pendant qu’il n’est pas jumelé (1/P):
      1. Trouver une chaussette avec un motif similaire
      2. Prenez une chaussette et comparez les deux (1)
      3. Si ok, stocker la paire

Cela dépend maintenant de notre capacité à trouver des paires correspondantes. Cela est particulièrement vrai si vous avez des paires sombres/grises ou des chaussettes de sport blanches qui ont souvent des motifs très similaires! Admettons que vous avez une probabilité de P de trouver la chaussette correspondante. Vous aurez besoin en moyenne de 1/P avant de trouver la chaussette correspondante pour former une paire. La complexité globale est de 1 + (n/2) * (1 + 1/P) = O (n).

Les deux sont linéaires dans le nombre de chaussettes et sont des solutions très similaires. Modifions légèrement le problème et admettons que vous avez plusieurs paires de chaussettes similaires dans l'ensemble, et que c'est facile de stocker plusieurs paires de chaussettes en un seul mouvement (1 + ε ). Pour K modèles distincts, vous pouvez implémenter:

  1. Pour chaque chaussette (n):
    1. Prenez une chaussette au hasard (1)
    2. Mettez-le sur le cluster de son motif
  2. Pour chaque groupe (K):
    1. Prendre des grappes et stocker des paires de chaussettes (1 + ε)

La complexité globale devient n + K = O (n). Il est toujours linéaire, mais choisir le bon algorithme peut maintenant dépendre grandement des valeurs de P et K! Mais on peut encore objecter que vous pouvez avoir des difficultés à trouver (ou créer) un cluster pour chaque chaussette.

En outre, vous pouvez également perdre du temps en recherchant sur les sites Web le meilleur algorithme et en proposant votre propre solution :)

5
eldams

Vers un algorithme efficace pour jumeler des chaussettes à partir d'une pile

Conditions préalables

  1. Il doit y avoir au moins une chaussette dans la pile
  2. La table doit être suffisamment grande pour accueillir N/2 chaussettes (pire des cas), N étant le nombre total de chaussettes.

Algorithme

Essayer:

  1. Choisissez la première chaussette
  2. Posez le sur la table
  3. Choisissez la chaussette suivante et regardez-la (sauf peut-être une exception "plus de chaussettes dans la pile")
  4. Maintenant, scannez les chaussettes sur la table (lève une exception s'il ne reste plus de chaussettes sur la table)
  5. Y a-t-il une correspondance? a) oui => retirer la chaussette correspondante de la table b) non => mettre la chaussette sur la table (peut lancer la table n'est pas assez grande, sauf exception)

Sauf:

  • La table n'est pas assez grande:
    Mélangez soigneusement toutes les chaussettes non appariées, puis remettez-les en marche
    // cette opération créera une nouvelle pile et une table vide

  • Pas de chaussettes sur la table:
    Jeter (la dernière chaussette impaire)

  • Pas de chaussettes dans la pile:
    Sortie buanderie

Finalement:

  • S'il y a encore des chaussettes dans la pile:
    Passez à 3

Problèmes connus

L'algorithme entrera dans une boucle infinie s'il n'y a pas de table autour ou s'il n'y a pas assez de place sur la table pour accueillir au moins une chaussette.

Amélioration possible

En fonction du nombre de chaussettes à trier, le débit peut être augmenté en triant les chaussettes sur la table, à condition que l'espace disponible soit suffisant.

Pour que cela fonctionne, il faut un attribut ayant une valeur unique pour chaque paire de chaussettes. Un tel attribut peut être facilement synthétisé à partir des propriétés visuelles des chaussettes.

Triez les chaussettes sur la table en fonction de cet attribut. Appelons cet attribut 'couleur'. Disposez les chaussettes dans une rangée et placez les chaussettes de couleur plus foncée à droite (c'est-à-dire. Push_back ()) et les chaussettes de couleur plus claire à gauche (c'est-à-dire. Push_front ()).

Pour les énormes piles et en particulier les chaussettes inédites, la synthèse d'attributs peut nécessiter un temps considérable, de sorte que le débit diminue apparemment. Cependant, ces attributs peuvent être conservés en mémoire et réutilisés.

Certaines recherches sont nécessaires pour évaluer l'efficacité de cette amélioration possible. Les questions suivantes se posent:

  • Quel est le nombre optimal de chaussettes à jumeler en utilisant l’amélioration ci-dessus?
  • Pour un nombre donné de chaussettes, combien d'itérations sont nécessaires avant que le débit n'augmente?
    a) pour la dernière itération
    b) pour toutes les itérations globales

PoC conforme aux MCVE directives:

#include <iostream>
#include <vector>
#include <string>
#include <time.h>

using namespace std;

struct pileOfsocks {
    pileOfsocks(int pairCount = 42) :
        elemCount(pairCount<<1) {
        srand(time(NULL));
        socks.resize(elemCount);

        vector<int> used_colors;
        vector<int> used_indices;

        auto getOne = [](vector<int>& v, int c) {
            int r;
            do {
                r = Rand() % c;
            } while (find(v.begin(), v.end(), r) != v.end());
            v.Push_back(r);
            return r;
        };

        for (auto i = 0; i < pairCount; i++) {
            auto sock_color = getOne(used_colors, INT_MAX);
            socks[getOne(used_indices, elemCount)] = sock_color;
            socks[getOne(used_indices, elemCount)] = sock_color;
        }
    }

    void show(const string& Prompt) {
        cout << Prompt << ":" << endl;
        for (auto i = 0; i < socks.size(); i++){
            cout << socks[i] << " ";
        }
        cout << endl;
    }

    void pair() {
        for (auto i = 0; i < socks.size(); i++) {
            std::vector<int>::iterator it = find(unpaired_socks.begin(), unpaired_socks.end(), socks[i]);
            if (it != unpaired_socks.end()) {
                unpaired_socks.erase(it);
                paired_socks.Push_back(socks[i]);
                paired_socks.Push_back(socks[i]);
            }
            else
                unpaired_socks.Push_back(socks[i]);
        }

        socks = paired_socks;
        paired_socks.clear();
    }

private:
    int elemCount;
    vector<int> socks;
    vector<int> unpaired_socks;
    vector<int> paired_socks;
};

int main() {
    pileOfsocks socks;

    socks.show("unpaired socks");
    socks.pair();
    socks.show("paired socks");

    system("pause");
    return 0;
}
2
Laszlo

Mode plaisanterie sur

Je suis désolé de le dire, mais vous avez tous clairement tort. Pour votre cas d'utilisation réel, avec des chaussettes, vous pouvez réaliser des chaussettes parfaites sans aucun effort et en O (1).

Achetez simplement un sac de ceux-ci , attachez vos chaussettes tous les jours lorsque vous les tirez de vos pieds et quand elles sortent de la machine à laver, elles sont déjà jumelées comme par magie.

(Je ne suis en aucun cas affilié à ce vendeur, vous pouvez le trouver à plusieurs endroits)

mode plaisanterie désactivé

1
singe3

Deux axes de réflexion, la vitesse nécessaire pour trouver une correspondance, par rapport à la vitesse nécessaire pour rechercher toutes les correspondances par rapport au stockage.

Pour le second cas, je voulais signaler une version parallèle du GPU qui interroge les chaussettes pour toutes les correspondances.

Si vous souhaitez faire correspondre plusieurs propriétés, vous pouvez utiliser des nuplets groupés, des itérateurs Zip plus sophistiqués et les fonctions de transformation de poussée, par souci de simplicité, voici une requête basée sur un GPU:

//test.cu
#include <thrust/device_vector.h>
#include <thrust/sequence.h>
#include <thrust/copy.h>
#include <thrust/count.h>
#include <thrust/remove.h>
#include <thrust/random.h>
#include <iostream>
#include <iterator>
#include <string>

// Define some types for pseudo code readability
typedef thrust::device_vector<int> GpuList;
typedef GpuList::iterator          GpuListIterator;

template <typename T>
struct ColoredSockQuery : public thrust::unary_function<T,bool>
{
    ColoredSockQuery( int colorToSearch )
    { SockColor = colorToSearch; }

    int SockColor;

    __Host__ __device__
    bool operator()(T x)
    {
        return x == SockColor;
    }
};


struct GenerateRandomSockColor
{
    float lowBounds, highBounds;

    __Host__ __device__
    GenerateRandomSockColor(int _a= 0, int _b= 1) : lowBounds(_a), highBounds(_b) {};

    __Host__ __device__
    int operator()(const unsigned int n) const
    {
        thrust::default_random_engine rng;
        thrust::uniform_real_distribution<float> dist(lowBounds, highBounds);
        rng.discard(n);
        return dist(rng);
    }
};

template <typename GpuListIterator>
void PrintSocks(const std::string& name, GpuListIterator first, GpuListIterator last)
{
    typedef typename std::iterator_traits<GpuListIterator>::value_type T;

    std::cout << name << ": ";
    thrust::copy(first, last, std::ostream_iterator<T>(std::cout, " "));
    std::cout << "\n";
}

int main()
{
    int numberOfSocks = 10000000;
    GpuList socks(numberOfSocks);
    thrust::transform(thrust::make_counting_iterator(0),
                      thrust::make_counting_iterator(numberOfSocks),
                      socks.begin(),
                      GenerateRandomSockColor(0, 200));

    clock_t start = clock();

    GpuList sortedSocks(socks.size());
    GpuListIterator lastSortedSock = thrust::copy_if(socks.begin(),
                                                     socks.end(),
                                                     sortedSocks.begin(),
                                                     ColoredSockQuery<int>(2));
    clock_t stop = clock();

    PrintSocks("Sorted Socks: ", sortedSocks.begin(), lastSortedSock);

    double elapsed = (double)(stop - start) * 1000.0 / CLOCKS_PER_SEC;
    std::cout << "Time elapsed in ms: " << elapsed << "\n";

    return 0;
}

    //nvcc -std=c++11 -o test test.cu

Durée de fonctionnement pour 10 millions de chaussettes: 9 ms

1
JMan Mousey

Ma solution proposée suppose que toutes les chaussettes ont les mêmes détails, sauf par couleur. S'il y a plus de détails à différer entre les chaussettes, ces détails peuvent être utilisés pour définir différents types de chaussettes au lieu de couleurs dans mon exemple.

Étant donné que nous avons une pile de chaussettes, une chaussette peut être offerte en trois couleurs: bleu, rouge ou vert.

Ensuite, nous pouvons créer un opérateur parallèle pour chaque couleur; il a sa propre liste pour remplir les couleurs correspondantes.

At time i:

Blue  read  Pile[i]    : If Blue  then Blue.Count++  ; B=TRUE  ; sync

Red   read  Pile[i+1]  : If Red   then Red.Count++   ; R=TRUE  ; sync

Green read  Pile [i+2] : If Green then Green.Count++ ; G=TRUE  ; sync

Avec processus de synchronisation:

Sync i:

i++

If R is TRUE:
    i++
    If G is TRUE:
        i++

Cela nécessite une initialisation:

Init:

If Pile[0] != Blue:
    If      Pile[0] = Red   : Red.Count++
    Else if Pile[0] = Green : Green.Count++

If Pile[1] != Red:
    If Pile[0] = Green : Green.Count++

Best Case: B, R, G, B, R, G, .., B, R, G

Worst Case: B, B, B, .., B

Time(Worst-Case) = C * n ~ O(n)

Time(Best-Case) = C * (n/k) ~ O(n/k)

n: number of sock pairs
k: number of colors
C: sync overhead
1
Khaled.K