This commit is contained in:
Luc Dartois 2024-02-28 11:53:24 +01:00
parent 3014f7a3af
commit 5e7fc1594d
15 changed files with 0 additions and 530 deletions

122
TP/TP1.md
View File

@ -1,122 +0,0 @@
TP Graphes 1 : Codage de graphes
============
- - - - -
Exercice 1 : Matrice d'adjacence
----------
Un graphe sera représenté ici par une structure contenant un entier (son ordre), un entier booléen (orienté ou non), et son ensemble d'arêtes, représenté par sa matrice d'adjacence :
```
struct graphe{
int ordre; // l'ordre du graphe
int** adj; // la matrice d'adjacence, donnée par un double tableau dynamique
int oriente; // vaut 0 si le graphe est non orienté, 1 sinon
};
typedef struct graphe graphe;
```
**Question :**
Ecrire une fonction permettant de créer un graphe vide à partir de son ordre et de son orientation :
```
graphe creergraphe(int ord,int or);
```
La fonction devra entre autres réserver de la mémoire pour la matrice d'adjacence.
**Question :**
Ecrire une fonction prenant un graphe et deux sommets, et ajoutant une arête entre ces deux sommets :
```
void ajoutArete(graphe g,int v,int w){
```
**Question :**
Si le graphe est non orienté, toute arête de v vers w ajoute également une arête de w vers v.
Modifiez la fonction précédente pour en prendre compte.
**Question :**
Créez dans le main le graphe des frontières de la France (on ne considérera pas les micro-états).
- - - - -
Exercice 2 : Voisinage
----------
**Question :**
Ecrire une fonction permettant de d'afficher les voisins d'un sommet dans un graphe non orienté.
Testez votre fonction sur le graphe créé au premier exercice.
**Question :**
Modifiez votre fonction pour afficher les voisins sortants et les voisins entrants si le graphe est orienté.
**Question :**
Ecrire une fonction comptant le nombre de voisins d'un sommet dans un graphe, en gérant les cas orienté ou non orienté.
**Question :**
Vérifiez sur le graphe créé la propriété du cours :
La somme du nombre de voisins de tous les états est égal au nombre d'arêtes x 2.
- - - - -
Exercice 3 : Listes
----------
Il est possible de coder l'ensemble des voisins d'un sommet par une liste chaînée.
Pour cela, on utilise un codage des listes chaînées :
```
struct mail{
int valeur;
struct mail *suivant;
};
```
Ainsi que des fonctions les utilisant :
```
int tailleM(maillon *m){ //Renvoie la taille d'une liste
int res=0;
while(m!=NULL)){
res++;
m=m->suivant;
}
return res;
}
void affiche(maillon *m){ //Affiche le contenu d'une liste
if(m==NULL){
printf("\n");
}else{
printf("%d, ",m->valeur);
affiche(m->suivant);
}
}
maillon* ajouterDebut(maillon* m,int val){ //Renvoie la liste enrichie de val
maillon* res=malloc(sizeof(maillon));
res->valeur=val;
res->suivant=m;
return res;
}
int estDans(maillon* m,int val){ //Renvoie 0 si val n'est pas dans la liste, 1 sinon
if(m==NULL){
return 0;
}
if(m->valeur==val){
return 1;
}
return estDans(m->suivant,val);
}
```
A partir de ces listes, on peut donc définir un graphe comme suit :
```
struct graphe{
int ordre;
maillon** voisins;
int oriente;
};
```
Où voisins est un table de listes chaînées.
**Question :**
Recréez les fonctions codées dans les exercices précédents en les adaptant à cet encodage de graphes.
Normalement, vous devriez pouvoir utiliser la même fonction `main` pour tester votre code.

View File

@ -1,94 +0,0 @@
TP Graphes 2 : Chemins et connexité
============
Le TP est prévu pour être fait en utilisant le codage des graphes à l'aide de matrices d'adjacence.
- - - - -
Exercice 0 : Affichage
----------
***Question :***
Ecrire une fonction permettant d'afficher une matrice carrée (la taille de la matrice sera donnée en argument) :
```
void afficherMatrice(int **m,int taille);
```
**Question :**
Ecrire une fonction permettant d'afficher la matrice d'adjacence d'un graphe donné en argument :
```
void afficherAdjacence(graphe g);
```
- - - - -
Exercice 1 : Chemins de longueur fixe
----------
La multiplication de matrices carrées se fait grâce à la fonction de prototype :
```
int** multiplicationMatriceCarre(int **a,int **b,int size);
```
Le code de la fonction est donné ci-dessous. Si vous le souhaitez, vous pouvez ignorer le code et faire la fonction vous-même.
```
int** multiplicationMatriceCarre(int **a,int **b,int size){
int** res=calloc(size,sizeof(int*));
int i,j,k;
for(i=0;i<size;i++){
res[i]=calloc(size,sizeof(int));
}
for(i=0;i<size;i++){
for(j=0;j<size;j++){
for(k=0;k<size;k++){
res[i][j]+=a[i][k]*b[k][j];
}
}
}
return res;
}
```
**Question :**
En utilisant la multiplication de matrices carrées, créez une fonction renvoyant une matrice contenant les chemins d'une longueur donnée :
```
int** nombreDeChemins(graphe g,int longueur);
```
- - - - -
Exercice 2 : Connexité
----------
Un graphe (orienté) est (fortement) connexe si pour toute paire de sommet (x,y), il existe un chemin de x à y.
De plus, s'il existe un chemin de x à y, alors il en existe un de longueur *au plus* n, où n est l'ordre du graphe.
**Question :**
Ecrire la fonction `int estConnexe(graphe g);` renvoyant 1 si le graphe est connexe, et 0 sinon.
Indice : vous aurez besoin d'une fonction permettant d'additionner des matrices.
**Question :**
Testez votre fonction sur le graphe des frontières.
Créez un graphe similaire ayant en plus le Royaume-Uni. Vérifiez que ce graphe n'est pas connexe.
- - - - -
Exercice 3 : Graphe Eulériens
----------
***Question***
En utilisant le théorème d'Euler, écrire une fonction décidant si un graphe a un cycle eulérien.
Théorème d'Euler :
Un graphe est eulérien si, et seulement si, il est connexe et tous ses sommets sont de degré pair.
Bonus : Comment adapter votre fonction pour décider si un graphe a un *chemin* eulérien
- - - - -
Exercice 4 : Distance et diamètre.
----------
***Question***
Ecrire une fonction ```int** distances(graphe g);``` renvoyant une matrice dont le coefficient (i,j) contient la distance entre i et j.
Indice : Les sommets à distance 1 sont ceux qui sont adjacent (valeur 1 dans la matrice d'adjacence).
De façon générale, un sommet x est à distance l d'un sommet y si il existe un chemin de longueur l mais aucun chemin de longueur l-1.
***Question***
Ecrire une fonction ```int diametre(graphe g)``` retournant le diamètre du graphe passé en paramètre.

156
TP/TP3.md
View File

@ -1,156 +0,0 @@
TP Graphes 3 : Parcours et Coloration
============
Le TP est prévu pour être fait en utilisant le codage des graphes à l'aide de matrices d'adjacence.
Pour plus de clarté, vous pouvez utiliser un nouveau fichier, en copiant les structures et fonctions nécessaires depuis les TPs précédants.
- - - - -
Exercice 1 : Parcours en largeur
----------
Pour cet exercice, vous aurez besoin de file FIFO, dont voici la structure et les primitives :
```
struct file{
int data;
struct file* succ;
};
typedef struct file fifo;
void enqueue(fifo **fi,int v){
fifo *nf=malloc(sizeof(fifo));
nf->data=v;
nf->succ=*fi;
(*fi)=nf;
}
int dequeue(fifo **fi){
fifo *lect=*fi;
if(lect->succ==NULL){
int res=lect->data;
*fi=NULL;
return res;
}
while(lect->succ->succ!=NULL){
lect=lect->succ;
}
int res=lect->succ->data;
fifo *temp=lect->succ;
lect->succ=NULL;
free(temp);
return res;
}
int empty(fifo *fi){
return fi==NULL;
}
```
On rappelle que pour une variable `fifo *fi`, on empile 3 en faisant `enqueue(&fi,3)` et on défile (et on stocke dans une variable x) en faisant `x=dequeue(&fi)`.
**Question :**
Ecrire une fonction qui, étant donnés un graphe g et un sommet v de ce graphe, renvoie sous forme de file FIFO l'ensemble des voisins de v dans g :
```
fifo* fileVoisins(graphe g,int v);
```
![Parcours en Largeur](parcoursLargeur.png)
**Question :**
Ecrire une fonction effectuant le parcours en largeur d'un graphe g à partir d'un sommet v.
On pourra se contenter d'afficher sur la sortie standard la numérotation ainsi que les distances obtenues, plutôt que de les renvoyer :
```
void parcoursLargeur(graphe g,int v);
```
**Question :**
Tester sur un graphe (au hasard celui des frontières). Cela correspond-t-il à une exécution manuelle de l'algorithme ?
- - - - -
Exercice 2 : Parcours en profondeur
----------
Pour implémenter le parcours en profondeur d'un graphe, nous aurons besoin d'une pile, dont voici la structure et les primitives :
```
struct pile{
int head;
struct pile* suite;
};
typedef struct pile pile;
int emptyPile(pile *p){
return p==NULL;
}
void push(pile **p,int v){
pile* newpile=malloc(sizeof(pile));
newpile->head=v;
newpile->suite=*p;
*p=newpile;
}
int pop(pile **p){
int resultat=(*p)->head;
pile* temp=*p;
*p=(*p)->suite;
free(temp);
return resultat;
}
int first(pile *p){
return p->head;
}
```
On rappelle que pour une variable `pile *fi`, on push 3 en faisant `push(&fi,3)` et on dépile (et on stocke dans une variable x) en faisant `x=pop(&fi)`.
La primitive `x=first(fi)` permet de récupérer le sommet de la pile sans dépiler.
**Question :**
Ecrire une fonction effectuant le parcours en profondeur d'un graphe g à partir d'un sommet v.
On pourra se contenter d'afficher sur la sortie standard la numérotation de premier passage plutôt que de les renvoyer :
```
void parcoursProfondeur(graphe g,int v);
```
![Parcours en Profondeur](parcoursProfondeur.png)
**Question :**
Tester sur un graphe (au hasard celui des frontières). Cela correspond-t-il à une exécution manuelle de l'algorithme ?
**Question :**
Adaptez votre code pour également calculer, puis afficher, la numérotation de dernier passage.
- - - - -
Exercice 3 : Algorithme de Welsh-Powell
----------
On va implémenter l'algorithme de Welsh-Powell de coloriage glouton des graphes.
Les premières questions visent à donner des fonctions aidant à l'implémentation de l'algorithme. A vous de les suivre ou non.
**Question : Liste des sommets selon leur degré**
-Créer une fonction `int* tableauDegre(graphe g);` renvoyant un tableau où la case i contient le degré du sommet i.
-Créer une fonction `int indiceMax(int *tab,int taille);` renvoyant l'indice de la plus grande valeur du tableau tab de longueur taille.
-En utilisant les deux premières fonctions, créer une fonction `fifo* listeDegre(graphe g);` renvoyant une liste des sommets classés selon leur degré.
**Question**
Pour simplifier le code de Welsh-Powell, écrire une fonction
`int voisinCouleur(graphe g,int v,int c,int *color)` renvoyant 1 si le sommet v a un voisin de la couleur c dans le tableau color, et 0 sinon.
![Algorithme de Welsh-Powell](WelshPowell.png)
**Question**
Enfin, implémentez l'algorithme de Welsh-Powell.
Indice : Vous aurez besoin de la liste des sommets triés selon leur degré, mais également d'un lecteur sur cette liste, i.e. un pointeur vers le début de la liste pouvant la parcourir autrement que par des dequeues.

View File

@ -1,73 +0,0 @@
TP Graphes 4 : Plus Court Chemin et Arbre Recouvrant Minimal
============
Le TP est prévu pour être fait en utilisant le codage des graphes à l'aide de matrices d'adjacence.
Pour plus de clarté, vous pouvez utiliser un nouveau fichier, en copiant les structures et fonctions nécessaires depuis les TPs précédants.
- - - - -
Exercice 0 : Graphes valués
----------
Nous avons enrichi nos graphes avec une valuation des arêtes.
**Question :**
Comment intégrer cela à notre structure de données ?
Quel fonction(s) faut-il modifier pour prendre en compte cet enrichissement ?
**Question :**
Créez un nouveau fichier graphesvalues.c contenant la structure et les primitives nécessaires à la manipulation des graphes valués.
- - - - -
Exercice 1 : Algorithme de Dijkstra
----------
L'algorithme de Dijkstra renvoie deux données : la fonction d donnant la distance minimale entre la source et un sommet, et la fonction père donnant la direction à prendre pour atteindre cette distance minimale.
**Question :**
Une fonction des sommets vers un entier (ou un autre sommet) sera représentée par un tableau où la case i contient la valeur de la fonction pour i.
Le C ne permettant de renvoyer qu'une structure de données, comment permettre de renvoyer les deux fonctions ?
**Question :**
Implémentez l'algorithme de Dijsktra, que je redonne ci-dessous :
![Algorithme de Dijkstra](dijkstra.png)
**Question :**
Testez votre algorithme en reprenant le graphes des frontières avec des valuation de votre choix.
Vérifier à la main que l'algorithme effectue les bons calculs.
- - - - -
Exercice 2 : Algorithme de Prim
----------
Pour simplifier l'implémentation, on se contentera d'afficher sur la sortie standard les arêtes sélectionnées. On renverra tout de même la valuation totale de l'arbre couvrant.
![Algorithme de Prim](prim.png)
**Question (optionnelle) :**
Comme pour Dijkstra, l'ensemble des sommets atteint sera représenté par un tableau binaire.
Ecrivez une fonction `void selecArete(graphe g,int* atteint,int* x,int* y);`
qui trouve et dans le graphe g l'arête de poids minimale entre un sommet atteint et un sommet non atteint. Le résultat est stocké dans les arguments pointés x et y selon la nomenclature de l'algorithme.
**Question :**
Implémentez l'algorithme de Prim en vous aidant de la fonction de la question précédente, ou directement.
**Question :**
Testez et vérifiez votre implémentation sur un exemple, au hasard le graphe des frontières.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

View File

@ -1,85 +0,0 @@
#include<graph.h>
#include <math.h>
void visuelGraphe(graphe g){
int taille=1000;
int origine=taille/2;
int distance=4*origine/5;
int tailleVert=taille/20;
InitialiserGraphique();
CreerFenetre(10,10,taille,taille);
int i,j;
int x,y;
char* nV=malloc(2);
*nV='0';
*(nV+1)='\0';
int* cX=calloc(g.ordre,sizeof(int));
int* cY=calloc(g.ordre,sizeof(int));
for(i=0;i<g.ordre;i++){
x=(int) origine+distance*cos(2*M_PI*i/g.ordre);
y=(int) origine+distance*sin(2*M_PI*i/g.ordre);
cX[i]=x+tailleVert/2;
cY[i]=y+tailleVert/2;
RemplirArc(x,y,tailleVert,tailleVert,0,360);
EcrireTexte(x,y,nV,2);
(*nV)++;
}
//Version si le graphe est une matrice d'adjacence
for(i=0;i<g.ordre;i++){
for(j=0;j<g.ordre;j++){
if(g.adj[i][j]!=0){
DessinerSegment(cX[i],cY[i],cX[j],cY[j]);
}
}
}
//Version à utiliser si le graph est un tableau de listes chaînées
/*
maillon* read;
for(i=0;i<g.ordre;i++){
read=g.voisins[i];
while(read!=NULL){
DessinerSegment(cX[i],cY[i],cX[read->valeur],cY[read->valeur]);
read=read->suivant;
}
}
*/
Touche();
FermerGraphique();
}
//Aides matrices
//Creation matrice carrée vide :
int** creerMatriceId(int taille){
int** res=calloc(taille,sizeof(int*));
for(int i=0;i<taille;i++){
res[i]=calloc(taille,sizeof(int));
for(int j=0;j<taille;j++){
res[i][j]=(i==j)?1:0;
}
}
return res;
}
//Creation copie d'une matrice carree :
int** recopierMatrice(int **m,int taille){
int** creerMatriceId(int taille){
int** res=calloc(taille,sizeof(int*));
for(int i=0;i<taille;i++){
res[i]=calloc(taille,sizeof(int));
for(int j=0;j<taille;j++){
res[i][j]=m[i][j];
}
}
return res;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.