CS 315 TP4

publicité
CS 315 TP4
Algorithme de justification
o
un fichier
o
Size
o
o
o
just.c contenant une
int NbWords, const int* Lengths )
fonction
int* Justify( int Size,
est la largeur du paragraphe à justifier, NbWords le nombre
de mots dans le paragraphe, et Lengths la longueur de chacun
de ces mots
la fonction retourne un tableau d'entiers, de longueur variable,
contenant les indices des mots terminant chaque ligne du
paragraphe. Il est donc au minimum de taille 1, et son dernier
élément vaut forcément NbWords-1
la fonction ne doit PAS modifier les entrées
vous pouvez vous servir du fichier main.c afin d'entrer le
texte et afficher le résultat.
Ce TP d’algorithmique va nous permettre d’implémenter un algorithme de mise en
page, notamment ce qui concerne la justification d’un paragraphe. Le principe est le suivant :
on a un texte sous forme de mots et on veut mettre le mot sous forme « justifié ».
Pour cela : on essaie de serrer le texte pour que tout rentre sur une ligne et sinon soit
on envoie le mot sur la ligne suivante soit on le coupe en deux.
Nous commencerons par envisager seulement la possibilité d’envoyer le mot sur la
ligne suivante en espaçant la ligne.
On considère chaque cas (chaque ligne) au fur et a mesure du paragraphe, on traite le
problème localement, nous allons donc implémenter un algorithme de type : glouton.
L’idée de l’algorithme est :
Imaginons un texte de mots m1 à mN, avec des longueurs l1 à lN. On veut organiser en
colonne de taille C et en ligne (de longueur maxi c).
Tout d’abord on détermine la taille d’une ligne de mots mi à mj :
Taille ( i, j) = somme de longueur des mots + nb espaces
= somme des longueurs lk( pour k de i à j) +( j – i)
Algorithme de base glouton
On considère que S est l’indice du mot qui termine la ligne
Y est la ligne actuelle
N est l’indice du mot à la fin du paragraphe
S[0]=1
y=1
Pour x de S[y-1] à n,
Si taille (de S[y-1] à x) > à c
//On enlève dernier mot et on fait retour à la ligne c’est à dire
S[y ] <- x-1
y<- y+1
Fin si
Fin pour
S[y]=n
Cet algorithme est cependant un algorithme de base et il faudrait faire un algorithme plus
réfléchi.
En effet, cet algorithme se contente de faire un retour à la ligne lorsque le mot ne rentre pas
sur la ligne au coup par coup.
Nous voudrions, pouvoir optimiser notre paragraphe et faire en sorte de placer les mots de
façon a ce qu’on ait jamais de gros « trous ».
Exemple : alors qu’avec l’algorithme glouton, on aurait :
Bla bla bla bla bla bla bla bla bla
bla blabla bla bla bla bla bla bala
blablablablablablablablablab
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bb bbb bb
bbbbbbbb
Avec notre nouvel algorithme on aurait :
Bla bla
bla
bla
bla
bla bla bla bla bla bla blabla bla bla bla
bla bala blablablablablablablablablab bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bb bbb
bbb bb
On optimise les espaces.
Pour cela on essaie d’envisager le problème sous un autre angle.
On crée une variable appelée coût, celle-ci calcule la place vide que nous coûte chaque ligne.
En effet, si on ne place pas le mot en fin de ligne, il se peut que l’on ait de la place vide qui ne
sera pas remplie et qui coûte donc des ressources pour rien.
Ainsi, le paragraphe le mieux sera celui qui a le coût minimum.
Coût (li)= (C-li) ^3
Avec li est
Coût (total)= somme des coûts des li pour i de 1 à n
Algorithme naïf
Pour i=1 à…
Pour J=I à …
L1= taille de i à j
Pour k = j+i à …
L2= (l(j+k)….lk)
On se rend compte que l’on va calculer plusieurs fois les mêmes coûts, ce qui va rendre
l’algorithme plus complexe inutilement. On pourrait utiliser le coût trouvé précédemment et
ainsi de suite de façon récursive. On va alors implémenter l’algorithme en programmation
dynamique.
On recalcule alors une expression du coût :
Coût (1, i) = Coût (1, x) + Coût_ligne ( x+1, i)
Coût idéal ( 1, i) = min (entre x=1 a i) du Coût (1, x) + Cout_ligne ( x+1, i)
Algorithme de programmation dynamique :
On cherche le coût du paragraphe qui va de 1 à n
Pour i= 1 à n
// n mots dans le paragraphe, on parcourt donc le paragraphe
//cout idéal (1,i) ?
C[i]= infini
//initialisation de C afin qu’il soit maximum
Pour x=1 à i
//On parcourt chaque mot en partant du premier à chaque fois (c'est-à-dire : première
boucle, on ne parcourt que m1, puis deuxième boucle, on parcourt m1 et m2 puis troisième
boucle on parcourt m1, m2 et m3…)
C=C[x] + (C- taille(x+1, i))^3
// le coût est égal au coût de la nouvelle ligne plus le cout du nouveau mot
Si C< C[i]
// si ce coût est un minimum
C[i]<- C
// alors on enregistre ce minimum
X[i]<-x
// et on note l’indice du dernier mot de la ligne comme étant l’indice du
mot parcouru
Fin si
Fin pour
Fin pour
Le paragraphe se termine en X[n]. L’avant dernière ligne, se terminera en X[X[n]] et ainsi
l’avant avant dernière ligne se terminera en X[X[X[n]]]….
Cela revient à dire que l’on regarde le mot qui termine le paragraphe du mot qui termine le
paragraphe….
Pour la compréhension, on peut considérer que S[n] = X[n] et S[1] =
X[X[X[X[X…[X[n]]]]]…] et ceci autant de fois qu’il y a de lignes.
La complexité de l’algorithme précédent est :
n boucle « pour »,
n boucle « pour »
somme ( c-taille ( x…)) : teta de n
On a donc du n* n*n c’est à dire du teta n^3
Or, le coût est 0 si c’est la dernière ligne
Infini si taille ( i,j) >c
(c – taille (i,j))^3
D’où C/2 mots -> taille > c/2 + C/2 >C ???
On peut donc changer l’algorithme pour baisser sa complexité
Pour i= 1 à n
//on a n mots dans le paragraphe
//cout idéal (1,i) ?
C[i]= infini
//initialisation pour avoir C maximum car le bu t de l’algo est que C soit minimum
Pour x= i – (C /2) à i
C=D[x] + (C- taille(x+&, i))^3
Si C< C[i]
C[i]<- C
X[i]<-x
Fin si
Fin pour
Fin pour
La complexité devient du c*n²
On doit donc adapter cet algorithme en langage C et l’optimiser si possible !!
Pour la première ligne, les valeurs seront toutes minimales jusqu’à ce qu’on arrive à la fin de
la ligne où là, les valeurs seront vraiment minimales, on notera donc que l’on aura des valeurs
qui ne correspondent pas vraiment à un mini au début du tableau.
Téléchargement