#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>

using namespace std;

// individual connection data class
class RoomConnection {
  public:
    int roomin;
    int roomout;
    
    RoomConnection() {}
    RoomConnection(int n1, int n2) {
        roomin  = n1;
        roomout = n2;
    }
    
    void Print() {
        cout << "[" << roomin << ", " << roomout << "]";
    }
};

// list of connection data class
class RoomConnectionList : public vector<RoomConnection> {
  public:
    void push_back(RoomConnection rc) {
        vector<RoomConnection>::push_back(rc);
    }
    void push_back(int r1, int r2) {
        RoomConnection rc(r1 ,r2);
        push_back(rc);
    }
    
    void Print() {
        cout << "Room Connection List : " << size() << endl;
        for (vector<RoomConnection>::iterator it = begin(); it != end(); it++) {
            if (it != begin()) {
                cout << " ";
            }
            it->Print();
        }
        cout << endl;
    }
    
    // delete redundant connection
    // (if connection has duplicate data, result has also duplication)
    // eg. {1,2} {2,3} {1,2} {2,1} --> {1,2} {2,3}
    void Unique() {
        vector<RoomConnection>::iterator it, itstart, itend;
        for (it = begin(); it != end(); it++) {
            if (it->roomin > it->roomout) {
                std::swap(it->roomin, it->roomout);
            }
        }
        sort(begin(), end(), SortCmp);
        itstart = begin();
        itend =  unique(begin(), end(), UniqueCmp);
        assign(itstart, itend);
    }
    
  private:
    static bool SortCmp(RoomConnection a1, RoomConnection a2) {
        if (a1.roomin > a2.roomin) {
            return false;
        } else if (a1.roomin == a2.roomin) {
            if (a1.roomout > a2.roomout) {
                return false;
            }
        }
        return true;
    }
    static bool UniqueCmp(RoomConnection a1, RoomConnection a2) {
        if ((a1.roomin == a2.roomin) && (a1.roomout == a2.roomout)) {
            return true;
        }
        return false;
    }
};

// individual route class
class Route : public vector<int> {
  public:
    int Exist(int room) {
        for (vector<int>::iterator it = begin(); it != end(); it++) {
            if (*it == room) {
                return 1;
            }
        }
        return 0;
    }
    
    void Print() {
        cout << "[";
        for (vector<int>::iterator it = begin(); it != end(); it++) {
            if (it != begin()) {
                cout << ", ";
            }
            cout << *it;
        }
        cout << "]";
    }
};

// list of route class
class RouteList : public vector<Route> {
  public:
    void PrintMinimumRoute() {
        if (!size()) {
            cout << "No minimum route." << endl;
            return;
        }
        int minDistance = INT_MAX;
        for (vector<Route>::iterator it = begin(); it != end(); it++) {
            int size = (*it).size();
            minDistance = min(minDistance, size - 1);
        }
        cout << "Minimum Distance : " << minDistance << endl;
        cout << "--------------------------------" << endl;
        
        int numMinRoute = 0;
        for (vector<Route>::iterator it = begin(); it != end(); it++) {
            int size = (*it).size();
            if ((size - 1) == minDistance) {
                it->Print();
                cout << endl;
                numMinRoute++;
            }
        }
        cout << numMinRoute << " route found." << endl;
    }
    
    void Print() {
        cout << "All route" << endl;
        cout << "--------------------------------" << endl;
        for (vector<Route>::iterator it = begin(); it != end(); it++) {
            it->Print();
            cout << endl;
        }
    }
};

// find route with recursive
void FindRoute(RoomConnectionList *conList, int roomEnd, Route *route, RouteList *routeList)
{
    int lastRoom = route->back();
    int nextRoom;
    vector<RoomConnection>::iterator it;
    
    for (it =  conList->begin(); it != conList->end(); it++) {
        nextRoom = 0;
        if (it->roomin == lastRoom) {
            nextRoom = it->roomout;
        } else if (it->roomout == lastRoom) {
            nextRoom = it->roomin;
        }
        
        if (nextRoom) {
            if (!route->Exist(nextRoom)) { // avoid loop (back to same room?)
                Route tempRoute = *route;
                tempRoute.push_back(nextRoom);
                if (nextRoom == roomEnd) { // reach end room then add to list.
                    routeList->push_back(tempRoute);
                } else {
                    FindRoute(conList, roomEnd, &tempRoute, routeList);
                }
            }
        }
    }
}

// find all route (entry)
void FindAllRoute(RoomConnectionList *conList, int roomStart, int roomEnd, RouteList *routeList)
{
    Route tempRoute;
    
    tempRoute.clear();
    tempRoute.push_back(roomStart);
    FindRoute(conList, roomEnd, &tempRoute, routeList);
}

// main 
int main(void)
{
    RoomConnectionList roomConnection;
    RouteList route;
    
    // Room Connection List.
    roomConnection.push_back(1,2);
    roomConnection.push_back(1,3);
    roomConnection.push_back(1,4);
    roomConnection.push_back(2,5);
    roomConnection.push_back(3,5);
    roomConnection.push_back(4,5);
    roomConnection.push_back(2,6);
    roomConnection.push_back(3,6);
    roomConnection.push_back(4,6);
    roomConnection.push_back(5,7);
    roomConnection.push_back(6,7);
    
    int roomStart = 1;                // start room No.
    int roomEnd   = 7;                // end room No.
    
    roomConnection.Print();
    
    // check connection list (delete redundant connection)
    roomConnection.Unique();
    
    // find all route
    FindAllRoute(&roomConnection, roomStart, roomEnd, &route);
    
    // print result
    cout << "Start Room : " << roomStart << endl;
    cout << "End   Room : " << roomEnd << endl;
    cout << "There are " << route.size() << " different route." << endl;
    cout << endl;
    
    // print minimum distance
    route.PrintMinimumRoute();
    
    // print all route (for debug)
    //cout << endl << endl;
    //route.Print();
    
    return 0;
}

