Drop of Chaos (Construire une séquence minimalement apériodique)

9

L'idée ici est de produire un motif presque répétitif. C'est-à-dire que la séquence en cours de construction change au dernier moment pour éviter la répétition de certaines sous-séquences. Les conséquences de type AA et ABA sont à éviter (où B n'est pas plus long que A).

Exemples:

Je vais commencer et énumérer tous les petits exemples pour rendre ma description plus claire. Commençons par 0.

Valable: 0

Invalide: 00 (motif AA)
Valable: 01

Non valide: 010 (modèle ABA)
Non valide: 011 (modèle AA)
Valable: 012

Valable: 0120
Non valide: 0121 (modèle ABA)
Non valide: 0122 (motif AA)

Non valide: 01200 (modèle AA)
Non valide: 01201 (modèle ABA; 01-2-01)
Non valide: 01202 (modèle ABA)
Valable: 01203

Maintenant, je crois fermement qu'un a 4n'est jamais nécessaire, même si je n'ai pas de preuve, car j'ai facilement trouvé des séquences de centaines de caractères qui n'utilisent que 0123. (Cela est probablement étroitement lié à la façon dont seuls trois caractères sont nécessaires pour avoir des chaînes infinies sans motifs AA. Il y a une page Wikipedia à ce sujet.)

Entrée sortie

L'entrée est un entier unique, positif et non nul n. Vous pouvez supposer cela n <= 1000.

La sortie est une nséquence de caractères sans sous-séquence qui correspond à un motif interdit (AA ou ABA).

Exemples d'entrées et de sorties

>>> 1
0

>>> 2
01

>>> 3
012

>>> 4
0120

>>> 5
01203

>>> 50
01203102130123103201302103120132102301203102132012

Règles

  • Seuls les personnages 0123sont autorisés.
  • B n'est plus que A. Cela permet d' éviter la situation dans laquelle 012345doit être suivie 6parce 0123451a ceci: 1-2345-1. En d'autres termes, la séquence serait triviale et sans intérêt.
  • npeut être entré par n'importe quelle méthode souhaitée, à l' exception du codage en dur.
  • La sortie peut être une liste ou une chaîne, selon ce qui est le plus facile.
  • Pas de force brute ; le temps d'exécution doit être de l'ordre de quelques minutes, au plus une heure sur une machine très lente, pour n=1000. (Ceci est destiné à disqualifier les solutions qui ne font que boucler à travers toutes les npermutations de longueur {0,1,2,3}, de sorte que les trucs et astuces similaires sont interdits.)
  • Les failles standard sont interdites, comme d'habitude.
  • La notation est en octets. Il s'agit de , donc l'entrée la plus courte gagne (probablement - voir bonus).
  • Bonus: choisissez le chiffre le plus bas autorisé à chaque étape. Si 1et 3sont des choix possibles pour le chiffre suivant de la séquence, choisissez 1. Soustrayez 5 octets de votre score. Cependant, prenez note de la note ci-dessous.

Remarque!

Des impasses sont possibles. Votre programme ou fonction doit les éviter. Voici un exemple:

Souche: 012031021301231032013021031201321023012031021320123021031201302310320123021320310230120321023120130210312301320310213012032102301320312302103201231021301203102301320312302302
Souche: 012031021301231032013021031201321023012031021320123021031201302310320123021320310230120321023120130210312301320310213012032102301320312302103201231021301203102301320312302302
Souche: 0120310213012310320130210312013210230120310213201230210312013023103201230213203102301203210231201302103123013203102130120321023013203123021032012310213012031023013203123020
Souche: 012031021301231032013021031201321023012031021320123021031201302310320123021320310230120321023120130210312301320310213012032102301320312302103201231021301203102301320312302302

Chacune de ces séquences ne peut plus être étendue (sans utiliser a 4). Mais notez également qu'il existe une différence cruciale entre les deux premiers et les deux derniers. Je vais remplacer la sous-séquence initiale partagée par un Xpour rendre cela plus clair.

Souche: X2130120
Souche: X2130123
Souche: X320
Souche: X321301203102130

Les deux derniers chiffres de Xsont 10, donc les seuls choix possibles pour le chiffre suivant sont 2et 3. Le choix 2conduit à une situation où la séquence doit se terminer. L'algorithme gourmand ne fonctionnera pas ici. (Pas sans retour en arrière, de toute façon.)

El'endia Starman
la source
Peut-on utiliser une stratégie de force brute pour tester chaque chaîne possible, même si elle ne donnera pas de sortie en temps réel? Savez-vous qu'il existe une solution pour tous n? Si quelqu'un donne un algorithme heuristique semi-gourmand, comment vérifierez-vous qu'il ne rencontre pas de problèmes sur une très grande longueur? Le problème général est intéressant, et je n'ai pas pu trouver quoi que ce soit sur l'évitement de modèle où nous limitons la longueur d'une partie du modèle. Si quelqu'un peut produire une recette générale, je m'attends à ce que ce soit la meilleure approche.
xnor
Je crois que j'ai interdit la force brute dans les règles. Je devrais probablement souligner cela. Je n'ai pas de preuve qu'il existe une solution pour tous n, mais étant donné que les souches que mon programme trouve ont tendance à s'allonger de 10 chiffres en moyenne à chaque fois, je suis très sûr qu'une séquence infinie existe. Je ne sais pas comment un algorithme semi-gourmand pourrait être testé pour des séquences arbitrairement grandes. Je pourrais limiter l' exigence à n= 1000 et ne pas m'inquiéter de plus n.
El'endia Starman
4
Je suppose que AAc'est vraiment taper ABABest vide. Cela pourrait peut-être aider à rationaliser certaines solutions.
mathmandan

Réponses:

6

Rétine , 86 octets - 5 = 81

$
_
(r`^(?<-2>.)+_((.)+)\b$
$1!
\b$
0
3#
#
0#
1
1#
2
2#
3
)r`\1(?<-2>.)*((.)+)$
$0#
!
<empty>

<empty>représente une ligne de fin vide. Vous pouvez exécuter le code ci-dessus à partir d'un seul fichier avec l' -sindicateur.

L'entrée doit être donnée en unaire , par exemple 111111. Je ne l'ai pas encore testé pour une sortie de l'ordre de milliers - deux des expressions régulières peuvent devenir un peu lentes après un certain temps - mais il peut facilement en gérer quelques centaines en quelques secondes.

Explication

Il s'agit d'une simple solution de retour en arrière.

  1. Ajoutez a 0.
  2. Pendant que la séquence actuelle n'est pas valide, supprimez tous les 3 de fin et incrémentez le dernier non 3.
  3. Répétez jusqu'à ce que nous ayons une séquence valide de la longueur souhaitée.

Ce retour en arrière est implémenté par une boucle de substitutions d'expression régulière qui s'interrompt une fois que la chaîne reste inchangée à travers une itération.

$
_

Cela ajoute un _à l'entrée, qui est utilisé pour séparer l'entrée unaire de la séquence que nous construisons.

(r`^(?<-2>.)+_((.)+)\b$
$1!

Il s'agit de la première substitution dans la boucle (indiquée par le début (). Le regex correspond si a) il y a un caractère de mot (c'est-à-dire un chiffre) à la fin de la chaîne (ce qui signifie que la chaîne est valide - nous verrons ci-dessous que les séquences invalides sont marquées d'un caractère de fin #) et b) il y a au moins autant de caractères dans la séquence que dans l'entrée (ceci est vérifié à l'aide des groupes d'équilibrage ). Si tel est le cas, nous supprimons l'entrée et ajoutons a !. Cela !sert à faire échouer tous les regex dans la boucle, de sorte qu'elle se termine.

\b$
0

S'il y a un mot à la fin (c'est-à-dire que la séquence est valide et que la boucle n'a pas été terminée par l'étape précédente), ajoutez a 0.

3#
#

Si (à la place) la séquence avait été marquée comme invalide et terminée 3, nous la supprimons 3(mais laissons la séquence comme invalide, car il n'y a pas de suite possible pour le préfixe actuel ... donc le caractère suivant doit également être inversé).

0#
1
1#
2
2#
3

Si la séquence est marquée comme invalide et tout chiffre autre que celui 3à la fin, nous incrémentons le chiffre et retirons le marqueur.

)r`\1(?<-2>.)*((.)+)$
$0#

La dernière substitution dans la boucle (comme indiqué par le )). Il vérifie si la chaîne se termine par ABA(où Bn'est pas plus longue que Amais potentiellement vide). Les longueurs relatives de Aet Bsont à nouveau vérifiées à l'aide de groupes d'équilibrage, et la répétition de Aest vérifiée avec une simple référence arrière.

Si cette expression régulière correspond, nous marquons la séquence non valide en ajoutant #.

!
<empty>

Une fois la boucle terminée, tout ce que nous devons faire est de supprimer le !et nous nous retrouvons avec la sortie souhaitée.

Martin Ender
la source
2

Python 2, 175 - 5 = 170 octets

n=input();s='';u=j=-1
while n>len(s):
 while u>2:u=int(s[0]);s=s[1:]
 u+=1;t=`u`+s;m=c=0
 while t[c:]*0**m:c+=1;i=t[c:].find(t[:c]);m=j<i<=c
 if c>=len(t):s=t;u=j
print s[::j]

Il s'agit de l'algorithme gourmand avec retour en arrière. Je souhaite que ce soit plus court. J'espère que c'est correct (voir ci-dessous).

Il construit la chaîne un chiffre à la fois. Étant donné une chaîne de dchiffres qu'il a déjà trouvée, il essaie d'ajouter un 0comme (d+1)st chiffre. Si cela ne fonctionne pas, il essaie un 1, puis un 2, puis un 3. Si aucun de ces éléments ne fonctionne, il revient au dtroisième chiffre et l'incrémente (s'il est inférieur à 3) ou le supprime (s'il est égal à 3, auquel cas il incrémente le précédent, etc.).

Le contrôle de validité est la ligne avec .find. Dans le cas où quelqu'un décide de lire mon code, je dois dire que ce programme stocke en fait la chaîne à l'envers, ce qui signifie qu'il ajoute des chiffres à l' avant . La vérification implique donc de rechercher des endroits où les premiers c chiffres apparaissent à nouveau plus tard dans la chaîne (n'importe où après les premiers cchiffres), et s'il existe de tels endroits, si la longueur intermédiaire est au plus c.

(Bien sûr, il inverse la chaîne avant l'impression.)

Cela pourrait aussi être facilement plus rapide; À l'origine, je l'avais quitté plusieurs boucles tôt pour plus d'efficacité, mais cela coûtait de précieux octets. Il fait toujours OK dans la gamme de n=1000, cependant.

Quoi qu'il en soit, le programme semble montrer une préférence pour les petits chiffres, mais ce n'est pas une préférence très forte. Par exemple, l'exécuter avec n=2000m'a donné une chaîne avec des 523zéros, des 502uns, des 497deux et des 478trois, se terminant par 30210312013021. Donc, si quelqu'un d'autre travaille sur un algorithme gourmand, il peut peut-être confirmer ce résultat. Ou avec n=1000j'ai obtenu [263, 251, 248, 238]pour les comptes par chiffre.

Enfin, je mentionnerais que ces dénombrements suggèrent une sorte de symétrie, presque (mais pas exactement) comme si nous avions commencé avec une distribution uniforme, puis converti certains des 3`` en 0'' et quelques des 2`` en 1'' s. Mais évidemment, cela pourrait être juste une coïncidence. Je n'ai aucune idée!

mathmandan
la source
1

Haskell, 115 (120 octets - 5 bonus)

x?_|or[t x==t(drop i x)|i<-[1..length x],t<-[take$div(i+1)2]]=[]
x?0=[x]
x?n=(?(n-1)).(:x)=<<"0123"
f=reverse.head.([]?)

Courez en ligne sur Ideone

Exemple d'exécution:

*Main> f 40
"0120310213012310320130210312013210230120"
Anders Kaseorg
la source