Optimiser conditions while

Programath Messages postés 8 Statut Membre -  
mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   -
Re-bonjour,

Je sais je pose beaucoup de questions mais promis c'est la dernière :-)

Dans ce bout de mon programme je cherche à empêcher l'utilisateur de repasser 2 fois dans un même ville. J'utilise un vecteur
trajet
pour enregistrer les villes traversées et je questionne la machine pour vérifier si la ville est déjà enregistrée avant de l'afficher.

Mon problème n'est pas dans l'affichage, mais dans le
do ... while
. À moins de réécrire toutes les possibilités de while possible je ne vois pas comment empêcher l'utilisateur de re-sélectionner une ville où il est déjà passé.

Si vous avez une idée je suis preneur :-)

Merci d'avance

int saisie_villeB()
{
    int choix;

    cout << "Choisissez une ville: " << endl;

    for (size_t i = 0; i < trajet.size(); i++)
        if (trajet[i] != a)
            cout << "Choix 1: Ville A" << " taxe=+10" << endl;
    for (size_t i = 0; i < trajet.size(); i++)
        if(trajet[i] != c)
            cout << "Choix 3: Ville C" << " taxe=-50" << endl;
    for (size_t i = 0; i < trajet.size(); i++)
        if (trajet[i] != d)
            cout << "Choix 4: Ville D" << " taxe=+20" << endl;

    cout << endl;
    do {
        cout << "Saisissez votre choix: ";
        cin >> choix;
    } while(choix != 1 && choix != 3 && choix != 4);

    return choix;
}

2 réponses

  1. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   Ambassadeur 1 588
     
    bonjour,
    moi j'utiliserais des vecteurs supplémentaires, un pour les noms de ville, et un autre pour mémoriser si la ville a déjà été sélectionnée.

    ou bien, dans le while, j'appelerais une fonction qui vérifierait si la ville choisie est déjà dans le trajet.
    0
  2. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940
     
    Bonjour,

    Tu peux comme le suggères yg_be utiliser une structure auxiliaire, par exemple un
    std::set<std::string>
    qui stocke les villes déjà traversées. Si l'utilisateur saisit une valeur déjà présente dans cet ensemble, alors tu répètes la boucle
    do ... while
    . La recherche et l'insertion dans un
    std::set
    se fait en O(log(n)).

    Si tes villes sont représentées par un entier connu a priori, tu peux t'en sortir avec un vecteur ou un tableau, mais si tu as un très grand nombre de villes, ça n'est pas forcément l'idéal en terme de mémoire, mais l'accès ce fait en O(1) et est donc plus rapide.

    Voici ce que je te propose :

    #include <iostream>
    #include <ostream>
    #include <set>
    
    // Pour afficher facilement un std::set
    template <typename T>
    std::ostream & operator << (std::ostream & os, const std::set<T> & s) {
        for (const T & x : s) {
            os << x << ' ';
        }   
        return os;
    } 
    
    int main(){
        using namespace std;
        set<string> villes_traversees = {"Paris", "Londres"};
        while (villes_traversees.size() < 5) {
            string ville;
            cout << "Saisir un nom de ville, hormis " << villes_traversees << endl;
            std::getline(cin, ville);
            if (villes_traversees.find(ville) != villes_traversees.end()) {
                cerr << "Cette ville est déjà traversée !" << endl;
            } else {
                villes_traversees.insert(ville);
                cout << "Ville ajoutée !" << endl;
            }  
            cin.clear();
        }      
        cout << "Villes traversées : " << villes_traversees << endl;
        return 0;                      
    }


    Exécution :

    (mando@silk) (~) $ g++ toto.cpp -W -Wall && ./a.out 
    Saisir un nom de ville, hormis Londres Paris
    San Francisco
    Ville ajoutée !
    Saisir un nom de ville, hormis Londres Paris San Francisco
    Berlin
    Ville ajoutée !
    Saisir un nom de ville, hormis Berlin Londres Paris San Francisco
    Rio de Janeiro
    Ville ajoutée !
    Villes traversées : Berlin Londres Paris Rio de Janeiro San Francisco


    Remarque :

    Attention, car un
    std::set
    ordonne les éléments qu'il contient selon une relation d'ordre (ici implicitement l'ordre lexicographique). Si tu veux garder l'ordre de la saisie, tu peux donc peupler un container qui préservera l'ordre de la saisie, par exemple un
    std::vector
    ou une
    std::list
    .

    #include <list>
    #include <iostream>
    #include <ostream>
    #include <set>
    #include <string>
    
    // Pour afficher facilement un std::set
    template <typename T>
    std::ostream & operator << (std::ostream & os, const std::set<T> & s) {
        for (const T & x : s) {
            os << x << ' ';
        }   
        return os;
    } 
    
    // Pour afficher facilement un std::list
    template <typename T>
    std::ostream & operator << (std::ostream & os, const std::list<T> & s) {
        for (const T & x : s) {
            os << x << ' ';
        }   
        return os;
    } 
    
    int main(){
        using namespace std;
        list<string> trajet = {"Paris", "Londres"};
        set<string> villes_traversees = {"Paris", "Londres"};
        while (villes_traversees.size() < 5) {
            string ville;
            cout << "Saisir un nom de ville, hormis " << villes_traversees << endl;
            std::getline(cin, ville);
            if (villes_traversees.find(ville) != villes_traversees.end()) {
                cerr << "Cette ville est déjà traversée !" << endl;
            } else {
                villes_traversees.insert(ville);
                trajet.push_back(ville);
                cout << "Ville ajoutée !" << endl;
            }  
            cin.clear();
        }      
        cout << "Villes traversées : " << villes_traversees << endl;
        cout << "Trajet : " << trajet << endl;
        return 0;
    }
    


    Bonne chance
    0