diff --git a/cs677/hw1/Makefile b/cs677/hw1/Makefile new file mode 100644 index 0000000..83ab464 --- /dev/null +++ b/cs677/hw1/Makefile @@ -0,0 +1,12 @@ + +TARGET := minimum-energy + +all: $(TARGET) + +$(TARGET): $(TARGET).cc + $(CXX) -o $@ $^ + +.PHONY: test +test: + ./$(TARGET) test-impossible.txt + ./$(TARGET) test-long-short.txt diff --git a/cs677/hw1/cs677-hw1-nodes.txt b/cs677/hw1/cs677-hw1-nodes.txt new file mode 100644 index 0000000..505f350 --- /dev/null +++ b/cs677/hw1/cs677-hw1-nodes.txt @@ -0,0 +1,10 @@ +S1 +S6 +S1 S2 10 +S2 S3 8 +S2 S4 13 +S2 S5 24 +S2 S6 51 +S3 S4 14 +S4 S5 9 +S5 S6 17 diff --git a/cs677/hw1/minimum-energy.cc b/cs677/hw1/minimum-energy.cc new file mode 100644 index 0000000..7fceef4 --- /dev/null +++ b/cs677/hw1/minimum-energy.cc @@ -0,0 +1,202 @@ + +#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; + + Path() + { + cost = 0; + } + 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(); + + 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); + } + } + } + } +} diff --git a/cs677/hw1/test-impossible.txt b/cs677/hw1/test-impossible.txt new file mode 100644 index 0000000..f154078 --- /dev/null +++ b/cs677/hw1/test-impossible.txt @@ -0,0 +1,3 @@ +START +GOAL +START NOWHERE 1 diff --git a/cs677/hw1/test-long-short.txt b/cs677/hw1/test-long-short.txt new file mode 100644 index 0000000..d7e33d6 --- /dev/null +++ b/cs677/hw1/test-long-short.txt @@ -0,0 +1,13 @@ +START +GOAL + +START I1 10 +START I2 10 +START I3 1 +I1 GOAL 5 +I2 GOAL 4 +I3 I4 1 +I4 I5 1 +I5 I6 1 +I6 I7 1 +I7 GOAL 2