/* * Josh Holtrop * 2008-08-30 * Grand Valley State University * CS677 * Programming Assignment #1 */ #include #include #include #include #include using namespace std; /************************************************************************** * The Transition class holds a (cost, destination node) pair * *************************************************************************/ class Transition { public: int cost; string destination; }; /************************************************************************** * Path objects represent a path through the the graph starting at the * * start node. The Path object has a certain cost associated with it. * * The path may or may not end on the goal node. * *************************************************************************/ class Path { public: int cost; vector node_list; map visited_nodes; /* Default constructor */ Path() { cost = 0; } /* Construct a Path from another one, appending a new node from t */ Path(const Path & orig, const Transition & t) { cost = orig.cost + t.cost; node_list = orig.node_list; node_list.push_back(t.destination); visited_nodes = orig.visited_nodes; visited_nodes[t.destination] = true; } // comparison operator for making a min priority_queue bool operator()(const Path & p1, const Path & p2) { return p1.cost > p2.cost; } }; /* This function allows Path objects to be printed to ostream objects */ ostream & operator<<(ostream & out, const Path & p) { int sz = p.node_list.size(); out << '['; for (int i = 0; i < sz; i++) { out << p.node_list[i]; if (i < sz-1) out << ", "; } out << ']'; return out; } /************************************************************************** * Global type definitions * *************************************************************************/ typedef vector Transition_List_t; typedef map Transition_Table_t; /************************************************************************** * Function Prototypes * *************************************************************************/ void createTransition(Transition_Table_t & transitions, string src, string dest, int cost); void solveMinEnergy(string start, string goal, Transition_Table_t & transitions); /************************************************************************** * Main Function * *************************************************************************/ int main(int argc, char * argv[]) { if (argc != 2) { cerr << "Usage: minimum-energy " << endl; return 42; } ifstream i(argv[1]); if (!i.is_open()) { cerr << "Could not open " << argv[1] << endl; return 1; } string startNode; string goalNode; Transition_Table_t node_transitions; /* Read the input file */ i >> startNode; i >> goalNode; while (!i.eof()) { string src, dest; int cost; i >> src >> dest >> cost; createTransition(node_transitions, src, dest, cost); } i.close(); /* Once the input is read, try to find a path */ solveMinEnergy(startNode, goalNode, node_transitions); return 0; } /************************************************************************** * Add a new transition into the node_transitions table * *************************************************************************/ void createTransition(Transition_Table_t & transitions, string src, string dest, int cost) { if (transitions.find(src) == transitions.end()) { /* src is not a key in transitions, so insert a new one */ Transition_List_t tl; transitions[src] = tl; } Transition t; t.cost = cost; t.destination = dest; transitions[src].push_back(t); } /************************************************************************** * Solve the minimum energy problem for start node start, goal node goal, * * and transition table set transitions * *************************************************************************/ void solveMinEnergy(string start, string goal, Transition_Table_t & transitions) { priority_queue, Path> pathQueue; /* Create an initial path with just the starting node in it */ Path init; init.cost = 0; init.node_list.push_back(start); init.visited_nodes[start] = true; pathQueue.push(init); /* LOOP * IF there are no paths left in the pathQueue * THEN there is no path to the goal; exit loop * END IF * IF the shortest path in the pathQueue ends at the goal node, * THEN we are done; exit loop * END IF * Remove the shortest path in the pathQueue * FOR EACH transition from the last node in the shortest path * IF the destination of the transition has not been visited * yet in this path * THEN Add a new path to the pathQueue with the destination * node of the transition appended to the end of the path * END IF * END FOR EACH * END LOOP */ for (;;) { if (pathQueue.size() == 0) { cout << "There is no path from " << start << " to " << goal << "!" << endl; break; } if (pathQueue.top().visited_nodes.find(goal) != pathQueue.top().visited_nodes.end()) { cout << "The minimum-energy set of reactions follows the path " << pathQueue.top() << " with a energy cost of " << pathQueue.top().cost << endl; break; } Path p = pathQueue.top(); pathQueue.pop(); string last = p.node_list[p.node_list.size() - 1]; if (transitions.find(last) != transitions.end()) { for (int i = 0, sz = transitions[last].size(); i < sz; i++) { if (p.visited_nodes.find(transitions[last][i].destination) == p.visited_nodes.end()) { /* the destination has not yet been visited in this path */ Path newPath(p, transitions[last][i]); pathQueue.push(newPath); } } } } }