Mot factorisation en temps

12

Étant donné deux chaînes , nous écrivons pour leur concaténation. Étant donné une chaîne et entier , nous écrivons pour la concaténation de copies de . Maintenant donné une chaîne, nous pouvons utiliser cette notation pour la 'comprimer', c'est-à-dire que peut être écrit comme . Appelons le poids d'une compression le nombre de caractères qui y apparaissent, donc le poids de est deux, et le poids de (une compression d' ) est de trois (séparéS1,S2S1S2Sk1(S)k=SSSkSAABAAB((A)2B)2 ( ( A ) 2 B 2 ) ( A B ) 2 A A B A B A A((A)2B2)(AB)2AABABAA sont comptés séparément).

Considérons maintenant le problème du calcul de la compression "la plus légère" d'une chaîne donnée avec . Après réflexion, il existe une approche de programmation dynamique évidente qui s'exécute en ou selon l'approche exacte.S|S|=nO(n3logn)O(n3)

Cependant, on m'a dit que ce problème peut être résolu en temps , bien que je ne trouve aucune source sur la façon de le faire. Plus précisément, ce problème a été évoqué lors d'un récent concours de programmation (problème K ici , deux dernières pages). Au cours de l'analyse, un algorithme été présenté et, à la fin, la borne pseudo quadratique a été mentionnée ( ici à la marque de quatre minutes). Malheureusement, le présentateur n'a fait référence qu'à «un lemme de combinatoire de mots compliqué», alors maintenant je suis venu ici pour demander la solution :-)O(n2logn)O(n3logn)

Timon Knigge
la source
Juste une propriété aléatoire: si pour une chaîne nous avons , alors ce doit aussi être que [ J'ai corrigé une erreur ici], avec ayant une longueur (qui ne peut pas être plus longue que ou ). Je ne sais pas à quel point c'est utile. Si vous avez déjà trouvé que et que vous savez que contient au moins 2 caractères distincts, et que vous recherchez maintenant un plus court tel que , alors il vous suffit d'essayer les préfixes de longueur qui divise.SS=Xa=Yb Z pgcd ( | X | , | Y | ) X Y S = X a S Y S = Y b Y X | X |S=Z|S|/gcd(|X|,|Y|)Zgcd(|X|,|Y|)XYS=XaSYS=YbYX|X|
j_random_hacker
Le problème est que même après avoir réduit tous les possibles , vous devez toujours agréger la réponse par un DP cubique sur des sous-segments (c'est-à-dire ), il y a donc encore du travail à faire après cela ... D P [ l , r ] = min k D P [ l , k ] + D P [ k + 1 , r ]XaDP[l,r]=minkDP[l,k]+DP[k+1,r]
Timon Knigge
Je vois ce que tu veux dire. Je pense que vous avez besoin d'une sorte de relation de dominance qui empêche certaines valeurs de de devoir être testées - mais je n'ai pas pu en penser une. En particulier, j'ai considéré ce qui suit: Supposons que ait une factorisation optimale avec ; est-il possible qu'il existe une solution optimale dans laquelle est factorisé comme avec ? Malheureusement, la réponse est oui: pour , a une factorisation optimale , mais la factorisation optimale unique pour est .S [ 1 .. i ] S [ 1 .. i ] = X Y k k > 1 S X Y j Z j < k S = A B A B C A B C S [ 1..4 ] ( A B ) 2 S A B ( A B C ) 2kS[1..i]S[1..i]=XYkk>1SXYjZj<kS=ABABCABCS[1..4](AB)2SAB(ABC)2
j_random_hacker

Réponses:

1

Si je ne vous comprends pas, je pense que la factorisation du coût minimum peut être calculée en temps comme suit.O(n2)

Pour chaque indice i, nous calculerons un ensemble de valeurs pour comme suit. Soit le plus petit entier tel qu'il existe un entier satisfaisantPour ce , soit le plus grand avec cette propriété. Si aucun n'existe, définissez afin que nous sachions qu'il y a zéro pour cet indice.(pi,ri)=1,2,pi11r2

S[irpi1+1,ipi1]=S[i(r1)pi1+1,i].
pi1ri1rpiLi=0(pi,ri)

Soit le plus petit entier strictement supérieur à satisfaisant, de même, pour certains . Comme précédemment, prenez pour être le maximum ayant fixé . En général, est le plus petit nombre strictement supérieur à . Si aucun tel n'existe, alors .pi2(ri11)pi1

S[iri2pi2+1,ipi2]=S[i(ri21)pi2+1,i]
ri22ri2pi2pi(ri11)pi1piLi=1

Notez que pour chaque indice i, nous avons car les valeurs de augmentent géométriquement avec . (si existe, il n'est pas seulement strictement plus grand que mais plus grand que celui d'au moins Ceci établit l'augmentation géométrique. )Li=O(log(i+1))pipi+1(ri1)pipi/2

Supposons maintenant que toutes les valeurs nous soient données. Le coût minimum est donné par la récurrence entendu que pour nous définissons . Le tableau peut être rempli en temps .(pi,ri)

dp(i,j)=min{dp(i,j1)+1,min(dp(i,jrjpj)+dp(jrjpj+1,jpj))}
i>jdp(i,j)=+O(n2+njLj)

Nous avons déjà observé ci-dessus que en délimitant la somme terme par terme. Mais en fait, si nous regardons la somme entière, nous pouvons prouver quelque chose de plus net.jLj=O(jlog(j+1))=Θ(nlogn)

Considérons l'arbre de suffixe de l'inverse de (c'est-à-dire l'arbre de préfixe de S). Nous facturerons chaque contribution à la somme à un bord de afin que chaque bord soit facturé au plus une fois. Chargez chaque au bord émanant de et allant vers . Ici est la feuille de l'arbre préfixe correspondant à et nca désigne l'ancêtre commun le plus proche.T(S)SiLiT(S)pijnca(v(i),v(ipij))v(ipij)v(i)S[1..i]

Cela montre que . Les valeurs peuvent être calculées dans le temps par une traversée de l'arbre des suffixes mais je laisserai les détails à une édition ultérieure si quelqu'un est intéressé.O(iLi)=O(n)(pij,rij)O(n+iLi)

Faites-moi savoir si cela a du sens.

Mert Sağlam
la source
-1

Il y a votre chaîne initiale S de longueur n. Voici le pseudo-code de la méthode.

next_end_bracket = n
for i in [0:n]: # main loop

    break if i >= length(S) # due to compression
    w = (next_end_bracket - i)# width to analyse

    for j in [w/2:0:-1]: # period loop, look for largest period first
        for r in [1:n]: # number of repetition loop
            if i+j*(r+1) > w:
                break r loop

            for k in [0:j-i]:
                # compare term to term and break at first difference
                if S[i+k] != S[i+r*j+k]:
                    break r loop

        if r > 1:
            # compress
            replace S[i:i+j*(r+1)] with ( S[i:i+j] )^r
            # don't forget to record end bracket...
            # and reduce w for the i-run, carrying on the j-loop for eventual smaller periods. 
            w = j-i

J'ai intentionnellement donné peu de détails sur les "crochets d'extrémité" car il faut beaucoup d'étapes pour empiler et désempiler, ce qui rendrait la méthode principale peu claire. L'idée est de tester une éventuelle contraction supplémentaire à l'intérieur de la première. par exemple ABCBCABCBC => (ABCBC) ² => (A (BC) ²) ².

Donc, le point principal est de chercher d'abord les grandes périodes. Notez que S [i] est le ième terme de S qui saute tout "(", ")" ou puissance.

  • la boucle i est O (n)
  • la boucle j est O (n)
  • r + k-boucles est O (log (n)) car il s'arrête à la première différence

C'est globalement O (n²log (n)).

Optidad
la source
Il n'est pas clair pour moi que les boucles r et k sont O (log n) - même séparément. Qu'est-ce qui garantit qu'une différence est trouvée après au plus O (log n) itérations?
j_random_hacker
Dois-je bien comprendre que vous compressez goulûment? Parce que c'est incorrect, considérez par exemple ABABCCCABCCC que vous devez factoriser comme AB (ABC ^ 3) ^ 2.
Timon Knigge,
Oui, vous avez tout à fait raison à ce sujet, je dois y penser.
Optidad