1. 程式人生 > >圖論中最短路徑問題C++實現

圖論中最短路徑問題C++實現

City.h檔案
    #ifndef _CITY_H_  
    #define _CITY_H_  
      
    using namespace std;  
      
    class City {  
      
    public:  
      
        // 城鎮的名稱  
        string name;  
      
        // 簿記資訊  
        bool    visited;  
        int total_fee;  
        int total_distance;  
        string from_city;  
      
        //預設建構函式  
        City() : name(""), visited(false), total_fee(0),   
      
    total_distance(0), from_city("") {}  
      
        City(string const &s): name(s), visited(false),  
        total_fee(0), total_distance(0), from_city("") {}  
    };  
      
    #endif  

Road.h檔案
#ifndef _ROAD_H_  
#define _ROAD_H_  
  
#include <string>  
  
using namespace std;  
  
class Road {  
  
public:  
  
    int fee;  
    int distance;  
    string destination;  
  
    Road(string city, int f, int d) : fee(f),  
    distance(d), destination(city) {}  
}  
;  
  
#endif 
RoadSystem.h檔案
    #ifndef _ROADSYSTEM_H_  
    #define _ROADSYSTEM_H_  
      
    #include <iostream>  
    #include <fstream>  
    #include <map>  
    #include <list>  
    #include <queue>  
    #include <vector>  
      
    #include "Road.h"  
    #include "City.h"  
      
    using namespace std;  
      
    class Cheapest {  
      
    public:  
        Cheapest() {}  
      
        bool operator()(City* city1, City* city2) {  
      
            return city1->total_fee > city2->total_fee;  
        }  
      
    };  
      
      
    class RoadSystem {  
      
    private:  
        map<string, list<Road*> > outgoing_roads;  
        map<string, City*> cities;  
      
        void load_roads(const string& filename);  
        void reset(void);  
        string recover_route(const string& city);  
        pair<int, int> calc_route(string from, string to);  
      
    public:  
      
        RoadSystem(const string& filename);//帶引數的建構函式,從檔案中讀取地圖資訊  
        ~RoadSystem(void);//析夠函式  
      
        void output_cheapest_route(const string& from, const string& to, ostream& out);  
        bool is_valid_city(const string& name);  
    };  
      
    #endif  


RoadSystem.cpp檔案
派生到我的程式碼片

    #pragma warning (disable:4786)  
    #pragma warning (disable:4503)  
      
    #include "RoadSystem.h"  
      
    void RoadSystem::reset(void) {  
      
        map<string, City*>::iterator it;  
        for(it=cities.begin();it!=cities.end();++it) {  
            it->second->visited = false;  
            it->second->total_fee = INT_MAX;  
            it->second->total_distance = INT_MAX;  
            it->second->from_city = "";  
        }  
    }  
      
    string RoadSystem::recover_route(const string& city) {  
          
        string route;  
        string current = city;  
          
        while (current != "") {  
      
            route = current + route;  
            string prev = cities[current]->from_city;  
      
            if (prev != "") {  
                route = " -> " + route;  
            }  
            current = prev;  
        }     
      
        return route;  
    }  
      
      
    RoadSystem::RoadSystem(string const &filename) {  
          
        load_roads(filename);  
    }  
      
    RoadSystem::~RoadSystem(void) {  
      
        // 釋放城市資訊  
        map<string, City*>::iterator city_it = cities.begin();  
        for ( ; city_it != cities.end(); city_it++) {  
            delete city_it->second;  
        }  
          
        // 釋放道路資訊  
        map<string, list<Road*> >::iterator roads_it =  
            outgoing_roads.begin();  
        for ( ; roads_it != outgoing_roads.end(); roads_it++) {  
          
            list<Road*>::iterator road_it = roads_it->second.begin();  
            for ( ; road_it != roads_it->second.end(); road_it++) {  
                delete *road_it;          
            }  
        }  
    }  
      
    void RoadSystem::load_roads(string const &filename) {  
      
        ifstream inf(filename.c_str());  
        string from, to;  
        int fee, distance;  
      
        while ( inf.good() ) {  
      
            // 讀入出發城市,目的城市,費用和路程資訊  
            inf >> from >> to >> fee >> distance;  
      
            if ( inf.good() ) {  
              
                Road* s = new Road(to, fee, distance);  
          
                // 在cities容器中加入實體  
                if (cities.count(from) == 0) {  
                    cities[from] = new City(from);    
                    outgoing_roads[from] = list<Road*>();  
                }   
      
                if (cities.count(to) == 0) {  
                    cities[to] = new City(to);                                            
                    outgoing_roads[to] = list<Road*>();  
                }  
      
                // 為城市新增道路  
                outgoing_roads[from].push_back(s);    
      
            }  
        }  
      
        inf.close();  
    }  
      
    //輸出結果  
    void RoadSystem::output_cheapest_route(const string& from,  
                    const string& to, ostream& out) {  
      
        reset();  
        pair<int, int> totals = calc_route(from, to);  
          
        if (totals.first == INT_MAX) {  
            out <<"從"<< from << "到" << to << "之間不存在可達的路徑。"<<endl;  
        } else {  
            out << "從" << from << "到" << to << "之間最便宜的路徑需要花費"<< totals.first << "澳元。"<<endl;  
            out << "該路線全長" << totals.second << "千米。" <<endl;  
            cout << recover_route(to) << endl << endl;  
        }  
    }  
      
    bool RoadSystem::is_valid_city(const string& name) {  
      
        return cities.count(name) == 1;  
    }  
      
    //迪克斯特拉演算法計算最短路徑  
    pair<int, int> RoadSystem::calc_route(string from, string to) {  
      
        // 用優先佇列來獲得下一個費用最低的城市  
        priority_queue<City*, vector<City*>, Cheapest> candidates;  
        City* start_city = cities[from];  
          
        // 將起始城市新增到佇列中  
        start_city->total_fee = 0;  
        start_city->total_distance = 0;  
        candidates.push(start_city);  
      
        // 如果優先佇列不空則迴圈  
        while(!candidates.empty()) {  
      
            City* visiting_city;  
            visiting_city = candidates.top();  
            candidates.pop();  
      
            if (! visiting_city->visited) {  
                visiting_city->visited = true;  
      
                // 迴圈檢查與該城市相連的各條公路  
                list<Road*>::iterator it;  
                for(it= outgoing_roads[visiting_city->name].begin();  
                    it != outgoing_roads[visiting_city->name].end(); ++it) {  
      
                    City* next_city = cities[(*it)->destination];  
                    int next_fee = (*it)->fee + visiting_city->total_fee;  
      
                    // 迪克斯特拉演算法修改標記處  
                    if((next_fee < next_city->total_fee)  
                        && next_city->name != from ) {  
                        next_city->total_fee = next_fee;  
                        next_city->total_distance =  
                            (*it)->distance + visiting_city->total_distance;  
                        next_city->from_city = visiting_city->name;  
                        candidates.push(next_city);  
                    }  
                }  
            }  
        }  
      
        // 返回總的費用和總的路程  
        if (cities[to]->visited) {  
            return pair<int,int>(cities[to]->total_fee, cities[to]->total_distance);  
        } else {  
            return pair<int,int>(INT_MAX, INT_MAX);  
        }  
    }  

main.cpp檔案
派生到我的程式碼片

    #pragma warning (disable:4786)  
    #pragma warning (disable:4503)  
      
    #include <iostream>  
    #include <fstream>  
    #include <string>  
    #include <list>  
    #include <map>  
    #include <queue>  
      
    #include "City.h"  
    #include "Road.h"  
    #include "RoadSystem.h"  
      
    using namespace std;  
      
    int main() {  
      
        try {  
      
            RoadSystem rs("MapInformation.txt");  
      
            while (true) {  
      
                cerr << endl << endl <<"請輸入起點城市和終點城市: (退出請輸入'quit')"<<endl;  
      
                string from, to;  
                cin >> from;  
                if (from == "quit") break;  
                cin >> to;  
      
                if (rs.is_valid_city(from) && rs.is_valid_city(to)) {  
                    rs.output_cheapest_route (from, to, cout);  
                }  
                else {  
                    cout << "無此城市, 請確認後重試!"<<endl<<endl;  
                }  
      
            }  
      
            return EXIT_SUCCESS;  
      
        }  
        catch (exception& e) {  
            cerr << e.what() << endl;  
        }  
        catch (...) {  
            cerr << "程式出現異常, 請退出程式後重試。"<<endl;  
        }  
      
        return EXIT_FAILURE;  
    }  

MapInformation.txt檔案
    Deloraine Queenstown 42 176  
    Deloraine Oatlands 25 84  
    Deloraine Launceston 12 50  
    Hobart Oatlands 18 84  
    Launceston Deloraine 12 50  
    Launceston Swansea 35 134  
    Oatlands Deloraine 25 84  
    Oatlands Hobart 18 84  
    Oatlands Queenstown 60 260  
    Oatlands Swansea 22 113  
    Queenstown Oatlands 60 260  
    Queenstown Deloraine 42 176  
    Swansea Launceston 35 134  
    Swansea Oatlands 22 113  
    Burnie Devonport 10 49  
    Devonport Burnie 10 49