Mon ami m'a donné un problème qu'il dit être facile, mais je ne peux pas trouver un bon algorithme à utiliser pour le faire.
Vous obtenez une entrée de 100 mots anglais aléatoires. Vous devez trouver la plus longue chaîne de mots où la dernière lettre d'un mot correspond à la première lettre du mot suivant. Vous ne pouvez utiliser chaque mot qu'une seule fois.
Par exemple, si l'on vous donnait les mots "chat", "chien", "ça", la plus longue chaîne que vous pourriez faire serait "chat -> ça". Si on vous donnait les mots "souris", "orignal", "licorne", la plus longue chaîne que vous pourriez faire serait juste un mot (car aucun de ces mots ne lie). Si on vous donnait les mots "oiseau", "plat", "harb", la plus longue chaîne que vous pourriez faire serait "harb -> oiseau -> plat" (ou "plat -> harb -> oiseau" ou "oiseau - > plat -> harb ").
J'ai eu l'idée de modéliser cela comme un graphique cyclique dirigé. Chaque nœud serait juste un mot, avec des sommets allant à chaque mot / nœud commençant par la lettre de ce mot se terminant par.
+-------+ \ +------+
| cat |-----------| that |
+-------+ / +------+
| |
\|/ |
+-------+ / |
| the |--------------+
+-------+ \
Ce problème semble être une recherche de chemin la plus longue , qui est NP-Hard.
Y a-t-il une meilleure façon de le faire? Ou même une sorte d'algorithme d'approximation qui pourrait être utilisé? Ou un moyen d'exploiter les qualités de l'anglais pour réduire l'espace de recherche?
la source
Réponses:
Je pense que cela est lié au problème de chemin le plus long (LP) que vous avez mentionné, mais c'est un peu différent. La principale différence est que le problème LP a un degré de connectivité supérieur à celui de votre problème suggéré. En limitant vos connexions aux dernières et premières lettres, vous supprimez un grand nombre de combinaisons potentielles.
Voici comment je recommanderais d'aborder celui-ci:
next word
, répétez l'étape 5 jusqu'à la fin de la chaîne.Garde en tête que:
Vous devrez suivre la longueur des chaînes et disposer d'un mécanisme global pour identifier la chaîne la plus longue.
Vous devrez également supprimer chaque mot de la copie de travail du nombre de connexions afin d'éviter une boucle récursive.
À un moment donné, votre chaîne se terminera et vous devrez sélectionner un mot avec un décompte de connexion de 0.
Vous devrez peut-être recalculer les entrées / sorties lorsque les mots sont supprimés des listes de travail. À première vue, je ne pense pas que cela sera nécessaire car les ensembles globaux seront relativement petits. Si vous passez à 1 000 mots, le fait d'avoir un nombre statique peut ralentir la convergence de l'algorithme.
J'ai vu cela comme un problème d'emballage. Pour moi, les connexions à l'intérieur et à l'extérieur identifient la forme à emballer. Plus les connexions sont basses, plus la forme est étrange. Plus la forme est étrange, plus je veux l'emballer tôt car j'ai l'impression que les chances de pouvoir emballer une forme étrange diminuent plus tard dans la chaîne.
Par exemple:
la source
Si vous faites une matrice 26X26 pour représenter le graphique dirigé du sommet comme chaque alphabet et les mots comme bord. Par exemple, le mot - APPLE connecte le sommet A et E avec l'arête dirigée de A à E. Maintenant, le problème se réduit à trouver la plus grande piste eulérienne (chemin qui comprend le nombre maximal d'arêtes, en visitant chaque arête une fois avec la répétition possible des sommets) dans le graphique. L'un des algorithmes O (E) consisterait à partir de façon aléatoire à partir d'une paire de sommets. Trouvez un chemin entre eux. Alors continuez à détendre le chemin jusqu'à ce qu'il soit possible.
update @ GlenH7 J'ai résolu une question similaire sur www.hackerearth / jda récemment, il y avait des notes relatives par rapport à la meilleure solution et j'ai obtenu les notes les plus élevées avec l'approche suivante.
Liste donnée de mots. Trouvez la plus longue chaîne qui puisse être formée par eux. Une chaîne est valide si chaque mot commence par une lettre * se terminant à la fin du dernier mot.
Approch =
1) faire le graphique des alphabets comme des sommets et des mots comme des bords. Au lieu d'utiliser plusieurs arêtes, utilisez-en une dont le poids est égal au nombre d'arêtes.
2) trouver la composante fortement connectée du graphe avec des arêtes maximales. Jeter temporairement les autres bords.
3) Pour chaque sommet, faites son indegree égal à son outdegree.
4) Maintenant leur circuit eulérien existe dans le graphe. Trouve le.
5) Maintenant, dans le graphique restant (wrt graphique d'origine trouver le chemin le plus long avec le premier sommet dans la composante fortement connectée choisie. Je pense que c'est NP difficile.
6) Inclure le sentier ci-dessus dans le circuit Elérien convertissant le circuit eulérien en sentier.
Pourquoi - J'accepte que cette question est très probablement NP difficile (devinez, pas mathématiquement parlant). Mais l'approche ci-dessus fonctionne mieux quand il y a une longue liste (1000+) de mots uniformément distribués (c'est-à-dire non destinés à être wc pour l'approche ci-dessus). Supposons qu'après avoir converti la liste donnée en graphique mentionné ci-dessus, cela se révèle heureusement être un graphique eulérien (voir http://en.wikipedia.org/wiki/Eulerian_path pour les conditions), alors sans aucun doute, nous pouvons dire cette réponse à la question ci-dessus est P et est en fait le chemin eulérien dans le graphique (voir http://www.graph-magics.com/articles/euler.php pour une approche très simple à faire et voyez ceci pour vérifier que votre graphique a simple http://www.geeksforgeeks.org/strongly-connected-components/et sinon nettoyer temporairement d'autres petits scc car le chemin eulérien existe pour un seul scc). Ainsi, pour les cas non chanceux (qui sont presque tous des cas), j'essaie de les convertir en cas chanceux (c'est-à-dire que la condition de piste eulérienne est remplie). Comment faire ça? J'ai essayé d'augmenter la recherche de profondeur pour les arêtes non pertinentes (l'ensemble des arêtes dans un chemin partant du sommet avec un degré supérieur à l'indegree et se terminant au sommet avec un degré supérieur à l'indegree). L'augmentation de la recherche de profondeur signifie que j'ai d'abord recherché tout cet ensemble d'un bord dans le chemin, puis deux bords dans le chemin et ainsi de suite. Il peut sembler à première vue que la recherche en profondeur nécessiterait O (nœuds ^ i) donc la complexité temporelle totale de O (nœuds + nœuds ^ 2 + nœuds ^ 3 + ....) jusqu'à ce que ce soit un cas chanceux. Mais l'analyse amortie révélera qu'il s'agit de O (bords). Une fois qu'il est réduit, le cas chanceux trouve le circuit eulérien.
Jusqu'ici, c'était tout le temps polynomial. Cela donnerait presque la meilleure solution. Mais pour augmenter encore votre solution (la solution parfaite est NP difficile) essayez une approche gourmande dans le graphique restant pour trouver une longue traînée fixant l'un des sommets dans le scc choisi. Ajoutez maintenant ceci à la piste eulérienne trouvée ci-dessus pour l'augmenter encore.
la source
Idée:
Tout d'abord, créez deux cartes (hachages), disons, S et E, des lettres de l'alphabet aux mots; le premier, S, associe les lettres de départ aux mots, le second, E, fait de même avec les lettres de fin.
Par exemple, si le dictionnaire est composé de:
oiseau, plat, chien, harb
nous avons:
et,
Ensuite, en utilisant S et E pour des recherches rapides, créez une forêt (ensemble d'arbres), de la même taille que le dictionnaire, avec des racines à chaque mot, et ne permettant pas à un mot d'apparaître plus d'une fois dans un arbre - cachez le les profondeurs des arbres lorsque vous les construisez:
Enfin, parcourez la forêt et trouvez le ou les arbres les plus profonds.
La ou les solutions seront sur l'axe descendant de ces arbres.
Par exemple,
au dessus de.
la source