/// <summary> /// Retourne une solution par ordre d'apparition dans le fichier /// </summary> /// <param name="parser">DataParser à utiliser</param> /// <param name="loadConstraint">Contrainte de chargement</param> /// <returns>Solution générée</returns> public static CVRPSolution OrderedSolution(DataParser parser, double loadConstraint) { CVRPSolution sol = _AddVars(parser); //Génère une instance de la solution sol.addNewRoute(parser); //Créé une nouvelle route //On fixe les variables for (int i = 0; i < parser.nodeList.Count; i++) { sol.setVariable(i, parser, loadConstraint); } sol.endSolution(); //On termine la solution return(sol); }
/// <summary> /// Retourne une solution par la méthode des plus prches voisins /// </summary> /// <param name="parser">DataParser à utiliser</param> /// <param name="loadConstraint">Contrainte de chargement</param> /// <returns>Solution générée</returns> public static CVRPSolution PPVSolution(DataParser parser, double loadConstraint) { CVRPSolution sol = _AddVars(parser); //Génère une instance de la solution sol.addNewRoute(parser); //Créé une nouvelle route sol.setVariable(0, parser, loadConstraint); //Fixe le dépot dans la route double[,] arcWeight = (double[, ])parser.arcWeight.Clone(); //Créé une copie de la matrice des distance //On boucle tant que tout les clients ne sont pas servis while (sol.freeVarCount != 0) { int nearestId = 0; //On initialise le plus proche voisin double distance = arcWeight[sol.varsIdList[sol.varsIdList.Count - 1], 0]; //On initialise sa distance au dernier point visité //On parcours tout les voisins potentiels for (int j = 1; j < parser.nodeList.Count; j++) { //Si l'arc vers j est réalisable et meilleur que les précédents considérés if (arcWeight[sol.varsIdList[sol.varsIdList.Count - 1], j] != 0 && (distance == 0 || arcWeight[sol.varsIdList[sol.varsIdList.Count - 1], j] < distance)) { //On met à jour le plus prche voisin nearestId = j; distance = arcWeight[sol.varsIdList[sol.varsIdList.Count - 1], j]; } } //Si on revient au dépot, on créé une nouvelle solution if (nearestId == 0) { sol.endRoute(); } else { sol.setVariable(nearestId, parser, loadConstraint); //On fixe le plus proche voisin } //On empêche le plus proche voisin d'être de nouveau disponible for (int j = 0; j < parser.nodeList.Count; j++) { arcWeight[j, nearestId] = 0; } } sol.endSolution(); //On termine la solution return(sol); }
/// <summary> /// Retourne une solution par la méthode de Clarke and Wright /// </summary> /// <param name="parser">DataParser à utiliser</param> /// <param name="loadConstraint">Contrainte de chargement</param> /// <returns>Solution générée</returns> public static CVRPSolution ClarkeWrightSolution(DataParser parser, double loadConstraint) { CVRPSolution sol = _AddVars(parser); //Génère une instance de la solution //On initialise la liste des savings List <KeyValuePair <Tuple <int, int>, double> > savings = new List <KeyValuePair <Tuple <int, int>, double> >(); int j; //On génère les savings for (int i = 1; i < parser.nodeList.Count; i++) { for (j = 1; j < parser.nodeList.Count - 1; j++) { int realJ = j; //On évite l'arc i->i if (j >= i) { realJ++; } savings.Add(new KeyValuePair <Tuple <int, int>, double>(new Tuple <int, int>(i, realJ), parser.arcWeight[0, realJ] + parser.arcWeight[i, 0] - parser.arcWeight[i, realJ])); } } //On trie la liste savings.Sort( delegate(KeyValuePair <Tuple <int, int>, double> pair1, KeyValuePair <Tuple <int, int>, double> pair2) { return(pair1.Value.CompareTo(pair2.Value)); }); savings.Reverse(); //On la renverse (ordre décroissant) List <List <int> > routes = new List <List <int> >(); //Liste des routes de la solution List <double> routeDist = new List <double>(); //Liste des distances associés à chaques routes List <double> routeCosts = new List <double>(); //Liste des coûts associés à chaques routes //On initialise les routes initiales for (int i = 1; i < parser.nodeList.Count; i++) { routes.Add(new List <int>(new int[] { i })); routeDist.Add(parser.arcWeight[0, i] + parser.arcWeight[i, 0]); routeCosts.Add(parser.nodeList[i].quantity); } j = 0; //Tant que la solution while (j < savings.Count - 1 && savings[j].Value >= 0) { Tuple <int, int> couple = savings[j].Key; //On récupère les noeuds associés au saving //On vérifie que les deux noeuds peuvent être fusionnés object[] res = _areMergeable(couple.Item1, couple.Item2, routes, routeDist, routeCosts, savings[j].Value, loadConstraint); //Si ils peuvent être fusionné if ((bool)res[0]) { routes[(int)res[1]] = routes[(int)res[1]].Concat(routes[(int)res[2]]).ToList(); //On créé la nouvelle route routeDist[(int)res[1]] = (double)res[4]; //On met à jour la distance de la route routeCosts[(int)res[1]] = (double)res[3]; //On met à jour le coût de la route routes.RemoveAt((int)res[2]); //On suppprime l'ancienne route routeDist.RemoveAt((int)res[2]); routeCosts.RemoveAt((int)res[2]); //On supprime le coût associé } j++; } //On créé la solution foreach (List <int> r in routes) { sol.addNewRoute(parser); foreach (int node in r) { sol.setVariable(node, parser, loadConstraint); } sol.endSolution(); } return(sol); }