[Cette question est un suivi pour calculer les exécutions d'une chaîne ]
Une période
p
d'une chaînew
est un entier positifp
tel quew[i]=w[i+p]
chaque fois que les deux côtés de cette équation sont définis. Soitper(w)
la taille de la plus petite période dew
. On dit qu'une chaînew
est périodique ssiper(w) <= |w|/2
.
Donc, officieusement, une chaîne périodique n'est qu'une chaîne composée d'une autre chaîne répétée au moins une fois. La seule complication est qu'à la fin de la chaîne, nous n'avons pas besoin d'une copie complète de la chaîne répétée tant qu'elle est répétée dans son intégralité au moins une fois.
Par exemple, considérez la chaîne x = abcab
. per(abcab) = 3
comme x[1] = x[1+3] = a
, x[2]=x[2+3] = b
et il n'y a pas de période plus courte. La chaîne abcab
n'est donc pas périodique. Cependant, la chaîne ababa
est périodique comme per(ababa) = 2
.
Comme plus d' exemples, abcabca
, ababababa
et abcabcabc
sont également périodiques.
Pour ceux qui aiment les regex, celui-ci détecte si une chaîne est périodique ou non:
\b(\w*)(\w+\1)\2+\b
La tâche consiste à trouver toutes les sous- chaînes périodiques maximales dans une chaîne plus longue. Celles-ci sont parfois appelées « runs» dans la littérature.
Une sous
w
- chaîne est une sous-chaîne périodique maximale (run) si elle est périodique et niw[i-1] = w[i-1+p]
ni niw[j+1] = w[j+1-p]
. De manière informelle, le «run» ne peut pas être contenu dans un «run» plus grand avec la même période.
Étant donné que deux exécutions peuvent représenter la même chaîne de caractères se trouvant à différents endroits de la chaîne globale, nous représenterons les exécutions par intervalles. Voici la définition ci-dessus répétée en termes d'intervalles.
Une exécution (ou sous-chaîne périodique maximale) dans une chaîne
T
est un intervalle[i...j]
avecj>=i
, tel que
T[i...j]
est un mot périodique avec la périodep = per(T[i...j])
- C'est maximal. Formellement, ni
T[i-1] = T[i-1+p]
niT[j+1] = T[j+1-p]
. De manière informelle, l'exécution ne peut pas être contenue dans une exécution plus grande avec la même période.
Indique RUNS(T)
l'ensemble des exécutions en chaîne T
.
Exemples de runs
Les quatre sous - chaînes périodiques maximale (runs) en chaîne
T = atattatt
sontT[4,5] = tt
,T[7,8] = tt
,T[1,4] = atat
,T[2,8] = tattatt
.La chaîne
T = aabaabaaaacaacac
contient les 7 sous - chaînes périodiques maximales suivantes (runs):T[1,2] = aa
,T[4,5] = aa
,T[7,10] = aaaa
,T[12,13] = aa
,T[13,16] = acac
,T[1,8] = aabaabaa
,T[9,15] = aacaaca
.La chaîne
T = atatbatatb
contient les trois exécutions suivantes. Ils sont:T[1, 4] = atat
,T[6, 9] = atat
etT[1, 10] = atatbatatb
.
Ici, j'utilise l'indexation 1.
La tâche
Écrivez le code de sorte que pour chaque entier n commençant à 2, vous produisiez le plus grand nombre d'exécutions contenues dans n'importe quelle chaîne binaire de longueur n
.
But
Votre score est le plus élevé que n
vous atteignez en 120 secondes de sorte que pour tous k <= n
, personne d'autre n'a posté une réponse correcte plus élevée que vous. De toute évidence, si vous avez toutes les réponses optimales, vous obtiendrez le score le plus élevé que n
vous publiez. Cependant, même si votre réponse n'est pas optimale, vous pouvez toujours obtenir le score si personne d'autre ne peut le battre.
Langues et bibliothèques
Vous pouvez utiliser toutes les langues et bibliothèques disponibles que vous aimez. Dans la mesure du possible, il serait bon de pouvoir exécuter votre code, veuillez donc inclure une explication complète sur la façon d'exécuter / compiler votre code sous Linux si possible.
Exemple optima
Dans ce qui suit: n, optimum number of runs, example string
.
2 1 00
3 1 000
4 2 0011
5 2 00011
6 3 001001
7 4 0010011
8 5 00110011
9 5 000110011
10 6 0010011001
11 7 00100110011
12 8 001001100100
13 8 0001001100100
14 10 00100110010011
15 10 000100110010011
16 11 0010011001001100
17 12 00100101101001011
18 13 001001100100110011
19 14 0010011001001100100
20 15 00101001011010010100
21 15 000101001011010010100
22 16 0010010100101101001011
Que doit exactement sortir mon code?
Pour chacun, n
votre code doit sortir une seule chaîne et le nombre d'exécutions qu'il contient.
Ma machine Les horaires seront exécutés sur ma machine. Il s'agit d'une installation ubuntu standard sur un processeur AMD FX-8350 à huit cœurs. Cela signifie également que je dois pouvoir exécuter votre code.
Réponses principales
- 49 par Anders Kaseorg en C . Simple thread et exécuté avec L = 12 (2 Go de RAM).
- 27 par cdlane en C .
la source
{0,1}
chaînes de caractères, veuillez l'indiquer explicitement. Sinon, l'alphabet pourrait être infini, et je ne vois pas pourquoi vos tests devraient être optimaux, car il semble que vous n'ayez recherché que les{0,1}
chaînes.n
jusqu'à12
et il n'a jamais battu l'alphabet binaire. Heuristiquement, je m'attendrais à ce qu'une chaîne binaire soit optimale, car l'ajout de caractères augmente la longueur minimale d'une exécution.Réponses:
C
Cela effectue une recherche récursive de solutions optimales, fortement élaguées en utilisant une limite supérieure sur le nombre d'exécutions qui pourraient être terminées par le reste inconnu de la chaîne. Le calcul de la borne supérieure utilise une gigantesque table de consultation dont la taille est contrôlée par la constante
L
(L=11
: 0,5 GioL=12
,: 2 GioL=13
,: 8 Gio).Sur mon ordinateur portable, cela passe par n = 50 en 100 secondes; la ligne suivante arrive à 142 secondes.
Sortie:
Voici toutes les séquences optimales pour n ≤ 64 (pas seulement lexicographiquement en premier), générées par une version modifiée de ce programme et de nombreuses heures de calcul.
Une séquence remarquable presque optimale
Les préfixes de la séquence fractale infinie
qui est invariant sous la transformation 101 ↦ 10100, 00 ↦ 101:
semblent avoir un nombre d'exécutions presque optimal - toujours à moins de 2 de l'optimal pour n ≤ 64. Le nombre d'exécutions dans les n premiers caractères divisé par n approches (13 - 5√5) / 2 ≈ 0,90983. Mais il s'avère que ce n'est pas le rapport optimal - voir les commentaires.
la source
Comme ce n'est pas une course s'il n'y a qu'un seul cheval, je soumets ma solution bien qu'elle ne soit qu'une fraction de la vitesse d'Anders Kaseorg et un tiers seulement comme cryptique. Compiler avec:
Le cœur de mon algorithme est un simple décalage et schéma XOR:
Une exécution de zéros dans le résultat XOR qui est supérieure ou égale à la période / décalage en cours indique une exécution dans la chaîne d'origine pour cette période. De là, vous pouvez dire combien de temps a duré la course et où elle commence et se termine. Le reste du code est une surcharge, la configuration de la situation et le décodage des résultats.
J'espère que cela fera au moins 28 après deux minutes sur la machine de Lembik. (J'ai écrit une version pthread, mais j'ai seulement réussi à la faire fonctionner encore plus lentement.)
Sortie:
la source
-O3
n'est pas censé être «dangereux». Il permet l'auto-vectorisation, mais il n'y a probablement rien à vectoriser ici. Il peut parfois ralentir le code, par exemple s'il utilise un cmov sans branche pour quelque chose où une branche aurait très bien prédit. Mais en général, cela devrait aider. Il vaut généralement aussi la peine d'essayer clang, pour voir lequel de gcc ou clang fait un meilleur code pour une boucle spécifique. En outre, il est presque toujours utile d'utiliser-march=native
, ou du moins-mtune=native
si vous voulez toujours un binaire qui s'exécute n'importe où.