TP - GPD

Transcription

TP - GPD
Université Paris 7 - Denis Diderot
IF2 : Structures de données et Objets JAVA
ème
semestre
Année 2006-2007, 2
L1 Sciences
TP n◦8
Récursivité
Exercice 1
Suite de Syracuse. La suite de Syracuse est dénie par la relation suivante :


u0 > 0
un+1 = un /2

un+1 = 3 ∗ un + 1
Dans une classe
Syracuse
si
si
un
un
est pair
est impair
:
1. Écrire une méthode récursive public static int syracuse(int
ième
le n
terme de la suite de Syracuse telle que u0 = init.
n,int init) qui calcule
2. écrire le code suivant dans une méthode :
int s, n=0;
while((s = syracuse(n,init)) != 1){
System.out.println(s);
n++;
}
Quel est le rôle de l'instruction ((s = syracuse(n,init)) != 1) ? Donnez la valeur que
vous voulez à init. Quelle est la condition d'arrêt de ce programme ? Pour quelles valeurs
d'entrée s'arrête-t-il ? Pouvez vous montrer qu'il s'arrête pour toutes les valeurs d'entrée ?
syracuse(n+1,init),
syracuse(n,init). Dénissez une méthode
void syracuseStop(int terme) qui :
3. le programme précédent n'est pas optimal : en eet, lors de l'appel de
on oublie que l'on a déjà calculé précédemment
statique récursive
ache à l'écran le terme courant.
calcule le terme suivant de la suite de syracuse (en fonction du terme précédent passé en
argument).
s'arrête si le terme courant vaut
1
et appelle
syracuseStop(termeSuivant)
sinon.
Testez le ensuite.
4. en fait, on sait (par des démonstrations informatiques) que pour (au moins) tout
il existe un rang
n
tel que
un = 1.
La méthode que vous avez programmée termine-t-elle
pour toute valeur passée en argument ? Et si les entiers sont codés sur
Exercice 2
u0 < 262 ,
64
bits ?
Sudoku.
Un principe simple de résolution d'un problème de Sudoku est : on prend la première case libre,
on met le chire
1 (si cela est autorisé par les règles), puis on essaye de résoudre (récursivement,
donc) le problème à partir de la case suivante. Si on n'y arrive pas, on essaye de mettre le chire
2, etc, etc. Ce principe n'est pas applicable pour un être humain, mais il marche raisonnablement
bien avec les ordinateurs, car ils ont une grande puissance de calcul. Le but de cet exercice est
d'écrire un programme permettant de résoudre tous les problèmes de Sudoku de taille
classe
Sudoku
contient les objets de type
Sudoku
1
:
9x9.
La
private de type int[][] nommé grille, qui sera de taille
9x9. Si le nombre de la case (i,j) est déjà connu (par l'initialisation), alors grille[i][j]
contient ce nombre, sinon il contient 0.
écrire un constructeur Sudoku(int[][] init) qui prend une grille init et la recopie dans
le champ grille de l'objet.
écrire une méthode String toString() qui retourne une chaîne de caractère associée à
1. chaque objet a un seul champ
2.
3.
l'objet (la représentation en mode texte de la grille). Par exemple, cela pourrait être :
-------+-------+------| 0 0 0 | 0 0 8 | 0 3 0 |
| 7 0 0 | 0 0 0 | 0 0 5 |
| 0 0 0 | 0 1 0 | 0 0 6 |
|-------+-------+-------|
| 0 0 9 | 0 0 5 | 0 0 2 |
| 0 7 8 | 0 9 0 | 6 0 0 |
| 0 4 5 | 0 0 3 | 0 0 9 |
|-------+-------+-------|
| 0 6 0 | 0 0 1 | 0 0 0 |
| 8 0 0 | 0 6 7 | 9 0 3 |
| 0 0 4 | 8 0 0 | 0 0 0 |
-------+-------+-------
ou bien, si l'on veut faire plus simple :
000008030
700000005
000010006
009005002
078090600
045003009
060001000
800067903
004800000
qui teste si
1
boolean nApparaitPasLigne(int nombre,int i, int j)
nombre n'apparaît pas sur la ligne i entre les indices j, j+1, ..., 8. N'oubliez
4. écrire une méthode récursive
pas le test d'arrêt ! Par exemple avec la grille ci-dessus, on a :
nApparaitPasLigne(5,3,0): false
nApparaitPasLigne(5,3,6): true
nApparaitPasColonne(int nombre,int i, int j)
qui teste si nombre n'apparaît pas sur la colonne j entre les indices i, ..., 8.
écrire une méthode itérative boolean nApparaitPasCarre(int nombre, int i, int j)
qui teste si nombre apparait dans le sous-carré de taille 3x3 associé à la case (i,j).
5. de même écrire une méthode récursive
6.
Indication : le coin supérieur gauche de ce sous-carré est repéré par les coordonnées
7.
8.
1
((i/3)*3,(j/3)*3) (pourquoi ?).
écrire une méthode boolean nombrePossible(int nombre, int i, int j) qui teste s'il
est possible de mettre nombre dans la case (i,j).
écrire une méthode boolean caseOccupee(int i, int j) qui teste si la case (i,j) est
déjà occupée. Par exemple, avec la grille précédente : jeu.caseOccupee(0,5) vaut true
tandis que jeu.caseOccupee(5,0) vaut false.
donc, ne contenant pas de boucle
2
9. écrire une méthode récursive
boolean resolution(int i,int j)
true s'il
grille) et
qui retourne
a réussi à résoudre le problème (et dans le même temps, remplit correctement
false sinon. (i,j) représente la case de départ de la résolution. L'algorithme suivi sera le
suivant :
test d'arrêt.
calcul de la case suivante.
si la case (i,j) est déjà occupée on résoud à partir de la case suivante.
sinon on essaye de mettre tour à tour tous les nombres dans la case, puis de
résoudre à partir de la case suivante.
si rien ne marche, on remet la case à 0 et on renvoie false.
10. enn, testez vos méthodes et la résolution.
3