Académique Documents
Professionnel Documents
Culture Documents
net/publication/358600281
CITATIONS READS
0 595
1 author:
Iyad Chehili
University of Science and Technology Houari Boumediene
3 PUBLICATIONS 0 CITATIONS
SEE PROFILE
All content following this page was uploaded by Iyad Chehili on 15 February 2022.
On doit établir une démarche générale permettant de résoudre le problème pour n'importe
quel ensemble de villes : cette démarche s'appelle un algorithme.
Les algorithmes pour résoudre le problème du voyageur de commerce peuvent être répartis en
deux classes :
- les algorithmes déterministes qui trouvent la solution optimale.
- les algorithmes d'approximation qui fournissent une solution presque optimale. Elles
permettent d'obtenir en un temps rapide de bonnes solutions, pas nécessairement optimales
mais de qualité suffisante.
Pour cette partie du projet, il est demandé de faire l’étude d’une méthode de résolution exacte
d’un problème NP-complet.
Nous passerons par l'approche naïve de la force brute pour résoudre le problème en utilisant
un concept mathématique connu sous le nom de "permutation".
Nous pouvons visualiser le problème en créant une structure de données de graphe ayant des
nœuds et des arêtes pondérées comme longueurs de chemin
Figure 3 le chemin le plus court couvrant tous les nœuds exactement une fois
Il y a quelques étapes classiques et faciles que nous devons suivre pour résoudre le problème
TSP.
Présentation de l’algorithme de résolution :
Les étapes d’exécution :
Vous aurez besoin d'un tableau à deux dimensions pour obtenir la matrice d’adjacence du
graphe donné.
Obtenez le nombre total de nœuds et le nombre total d'arêtes dans deux variables, à savoir
num_nodes et num_edges.
Créez un tableau multidimensionnel edge_list ayant la dimension égale à num_nodes *
num_nodes
Exécutez une boucle num_nodes time et prenez deux entrées, à savoir first_node et
second_node * à chaque fois comme deux nœuds ayant un bord entre eux et placez la
position edge_list[first_node] [second_node] égale à 1.
Après l'exécution de la boucle, nous avons une matrice d’adjacence disponible, c'est-à-
dire edge_list.
debut
// Obtenir le nombre de nœuds et le nombre d'arêtes en entrée
num_nodes, num_edges,i,j: entier ;
lire(num_nodes, num_edges) ;
//créer une matrice
edges_list[i][j] matrice d’entier;
pour i de 0 a num_nodes faire
debut
pour j de 0 a num_nodes faire
debut
edges_list[i][j] 0;
fin
fin
// mécanisme de remplissage de la matrice adjacente
pour i de 0 a num_edges faire
debut
first_node, second_node, weight : entier;
lire(first_node, second_node, weight) ;
edges_list[first_node] [second_node] weight;
edges_list[second_node] [first_node] weight;
fin
fin
Figure 4 pseudo code pour trouver la matrice adjacente du graphe
Code principal :
Public class brute_force
Debut
Fonction shortest_path_sum
Entree : edges_list : matrice [1..n][1..n] d’entier ;
num_nodes :entier ;
sortie : shortest_path : entier
debut
//Choisir une ville source
source : entier ;
nodes vecteur [1..n] d’entier;
// pousser le reste des villes num_nodes-1 dans un paquet
Pour i de 0 a num_nodes faire
debut
si (i <> source) alors
debut
nodes.push_back(i);
fin_si
fin
n, shortest_path: entier;
n nodes.size();
shortest_path INT_MAX;
//générer des permutations et suivre le coût minimum
Tantque (next_permutation(nodes.begin(), nodes.end())) faire
debut
i j,path_weight : entier;
path_weight0;
j source;
pour i de 0 a n faire
debut
path_weight path_weight + edges_list[j][nodes[i]];
j nodes[i];
finpour
path_weight path_weight +edges_list[j][source];
shortest_path min (shortest_path, path_weight);
fintantque
retourner(shortest_path) ;
fin_fonction
fin
var
debut
// Obtenir le nombre de nœuds et le nombre d'arêtes en entrée
num_nodes, num_edges,i,j: entier ;
lire(num_nodes, num_edges) ;
//créer une matrice
edges_list[i][j] matrice d’entier;
pour i de 0 a num_nodes faire
debut
pour j de 0 a num_nodes faire
debut
edges_list[i][j] 0;
fin
fin
// mécanisme de remplissage de la matrice adjacente
pour i de 0 a num_edges faire
debut
first_node, second_node, weight : entier;
lire(first_node, second_node, weight) ;
edges_list[first_node] [second_node] weight;
edges_list[second_node] [first_node] weight;
fin
Complexité théorique :
Temporelle :
Si l’ordinateur peut calculer un million de circuits Hamiltonien par seconde.
N=6 ;7 ;8 ;9 : instantanée
N=10 : environ 1/3 seconde
N=11 : environ 4 secondes
N=12 : environ 40 seconds
N=13 : environ 8 minutes
N=14 : près de 2 heures
N=15 : un peu plus d'une journée
N=20 : plus d'un million d'années
La complexité temporelle de l'algorithme dépend du nombre de nœuds. Si le nombre de
nœuds est n alors la complexité temporelle sera proportionnelle à N-1 ! (Factorielle de N-1)
soit O (N!).
Spatiale :
La plus grande quantité d'espace dans cet algorithme de graphe est prise par la matrice
adjacente qui est une matrice à deux dimensions N*N, où n est le nombre de nœuds. La
complexité spatiale est donc O(N2).
Pseudo code :
int main()
{
/// Getting the number of nodes and number of edges as input
int num_nodes,num_edges;
cin >> num_nodes >> num_edges; ///O(1)
for(int i=0;i<num_nodes;i++)
{
edges_list[i] = new int[num_nodes];
for(int j=0;j<num_nodes;j++)
{
edges_list[i][j] = 0; ///O(N²)
}
}
}
int a[100],distance=0;
for(int i=0;i<num_nodes;i++)
{
for(int j=0;j<num_nodes;j++)
{
cout << edges_list[i][j] << " "; ///O(N²)
}
cout << endl;
}
cout << endl << endl;/*
brute_force approach1;
cout << approach1.shortest_path_sum(edges_list,num_nodes) << endl;*/
///algorithme de verification
bool doubl=true;
int k,i=1;
//entrer la distance minimale
cout<<"entrer la distance minimale:"; ///O(1)
cin>>k; ///O(1)
//entrer le chemin
cout<<"donner le chemin:";
cin>>a[0];
do{
cin>>a[i]; ///O(n)
i++;
}while(a[i-1]!=a[0]);
//calcul de la distance
for(int j=0;j<i;j++){
distance+=edges_list[a[j]][a[(j+1)%i]]; ///O(n)
}
//tester si la distance est minimale ou non
if(distance<=k){ ///O(1)
cout<<"\nle chemin est "<<distance<<" il est optimale";}
else{cout<<"\nle chemin est "<<distance<<" il n'est pas optimale";}
//teste si un sommet est parcouru plus d'une fois
for(int l=1;l<i;l++){
for(int q=1;q<i;q++){
if(l!=q&&a[l]==a[q])doubl=false; ///O(n²)
}
}
//affichage des testes
if(i==num_nodes||!doubl) { ///O(n)
cout<<"\n mais tu ne pas parcouru toutes les sommets";}
else{
cout<<"\n tous les sommets sont parcourus";}
///end algorithm
return 0;
}
Figure 7 pseudo code pour l’algorithme de vérification
Complexité théorique :
Temporelle : O(f(n))
( N 2−N )
2
[
F ( n )= ( 1 ) + N + 2
2 ] + N +1+1+ N + N +1+ N 2 + N
7 N 2−7 N +8
F ( n )= [ 2 ]
T(N) = O(n2)
Spatiale :
La plus grande quantité d'espace dans cet algorithme de graphe est prise par la matrice
adjacente qui est une matrice à deux dimensions N*N, où n est le nombre de nœuds. La
complexité spatiale est donc O(N2).
int z=0,j;
int first_node,second_node,weight;
while(z<num_nodes-1)
{
j=z+1;
while(j<num_nodes)
{
first_node=z;
second_node=j;
weight=(rand()%15)+1;
edges_list[first_node][second_node] = weight;
edges_list[second_node][first_node] = weight;
j++;
}
z++;
}
N Complexité temporelle
4 0.001s
6 0.001s
8 0.002s
10 0.149s
11 1.389s
12 15.254s
13 251.94s
14 Environ 2 heures
15 Plus qu'une journée
20 Plus d'un million d'années
complexité théorique de l’algorithme de résolution
300
250
temps d'execution en Secondes
200
150
100
50
0
4 6 8 10 11 12 13
nombres de noeuds
Complexité spatiale :
L’espace mémoire dans cet algorithme de graphe est prise par la matrice d’adjacence qui est
une matrice à deux dimensions N*N, où n est le nombre de nœuds. La complexité spatiale est
donc O(N2).
N Complexité spatiale
4 16 octets
6 36 octets
8 64 octets
10 100 octets
11 121 octets
12 144 octets
13 169 octets
14 196 octets
16 256 octets
18 324 octets
20 400 octets
450
400
350
taille memoire en octets
300
250
200
150
100
50
0
4 6 8 10 12 14 16 18 20
N
N Complexité temporelle
4 0.008s
6 0.02s
10 0.034s
12 0.046s
20 0.146s
40 0.476s
60 1.359s
0.03
temps d'execution en Secondes
0.02
0.02
0.01
0.01
0
4 6 8 10 12 14 16
N
Complexité spatiale :
L’espace mémoire dans cet algorithme de graphe est prise par la matrice d’adjacence qui est
une matrice à deux dimensions N*N, où n est le nombre de nœuds. La complexité spatiale est
donc O(N2).
Donc c’est les mêmes résultats que l’algorithme précèdent.
Conclusion :
L'algorithme Brute-Force est une technique qui garantit des solutions aux problèmes de
n'importe quel domaine aide à résoudre les problèmes les plus simples et fournit également
une solution qui peut servir de référence pour évaluer d'autres techniques de conception
C’est un algorithme optimal mais inefficace. Il est garanti de trouver une solution, mais cela
peut prendre un temps déraisonnable pour le faire.
L'algorithme de force brute est utile pour résoudre des problèmes de petite taille, il est souvent
plus facile à mettre en œuvre qu'un autre plus sophistiqué et en raison de cette simplicité, il
peut parfois être plus efficace et aussi en l’utilise lorsque la simplicité est plus importante que
la vitesse.
Par contre les autres algorithmes comme plus proche voisin est efficace mais non optimal.
Donc c'est rapide et facile, mais on ne trouve pas toujours le circuit Hamilton le plus léger.
Références :
#include <bits/stdc++.h>
class brute_force
public:
int source = 0;
vector<int> nodes;
for(int i=0;i<num_nodes;i++)
if(i != source)
nodes.push_back(i);
int n = nodes.size();
while(next_permutation(nodes.begin(),nodes.end()))
{
int path_weight = 0;
int j = source;
path_weight += edges_list[j][nodes[i]];
j = nodes[i];
path_weight += edges_list[j][source];
return shortest_path;
};
int main()
int num_nodes,num_edges;
cout << "\n Donnez le nombre des noeuds puis le nombre d'aretes: ";
for(int i=0;i<num_nodes;i++)
for(int j=0;j<num_nodes;j++)
edges_list[i][j] = 0; ///O(N²)
cout << "\n donnez l'aretes et leur poids exemple:\n noeud1 noeud2 poids\
n";
for(int i=0;i<num_edges;i++)
int first_node,second_node,weight;
edges_list[first_node][second_node] = weight;
edges_list[second_node][first_node] = weight;
}
int a[100],distance=0;
for(int i=0;i<num_nodes;i++)
for(int j=0;j<num_nodes;j++)
brute_force approach1;
///algorithme de verification
bool doubl=true;
int k,i=1;
cin>>k; ///O(1)
//entrer le chemin
cout<<"donner le chemin:";
cin>>a[0];
do{
cin>>a[i]; ///O(n)
i++;
}while(a[i-1]!=a[0]);
//calcul de la distance
for(int j=0;j<i;j++){
distance+=edges_list[a[j]][a[(j+1)%i]]; ///O(n)
if(distance<=k){ ///O(1)
for(int l=1;l<i;l++){
for(int q=1;q<i;q++){
if(l!=q&&a[l]==a[q])doubl=false; ///O(n²)
if(i==num_nodes||!doubl) { ///O(n)
///end algorithm
return 0;
}
Figure 10 code source en C++