Skip to content

Commit

Permalink
Merge pull request #5 from gordon-cs/optimized
Browse files Browse the repository at this point in the history
Requirement 5 : Articulation Points
  • Loading branch information
jakedcolbert authored May 4, 2022
2 parents 854941c + 35e24f5 commit 2b3b759
Show file tree
Hide file tree
Showing 9 changed files with 288 additions and 81 deletions.
67 changes: 63 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,74 @@
# Author: Elijah Opoku-Nyarko and Jake Colbert

# define colors
ifneq (,$(findstring xterm,${TERM}))
RED := $(shell tput -Txterm setaf 1)
GREEN := $(shell tput -Txterm setaf 2)
RESET := $(shell tput -Txterm sgr0)
else
RED := ""
GREEN := ""
RESET := ""
endif

# default target
all: project5

# compile the code into an executable called 'project1' using C++ 2011
project5: project5.cc province.cc province.h
g++ -std=c++11 -o project5 project5.cc province.cc

# test the code against an expected output file
# this test should grow into a spaceship and end with blinkers
test-requirement1: project5
# test all the code
test-all: project5 test-nowhere test-one-road test-simple test-local test-combo
@echo ""
@echo "$(GREEN)Passed all tests!$(RESET)"
@echo ""

test: project5
./project5 < test-data/t0502-combo.in > test-data/project5.out
diff test-data/project5.out test-data/shortest.out > test.diff
rm test-data/project5.out

# test the code against an expected output file
test-nowhere: project5
@echo ""
@echo "$(RED)--- Nowhere Test ---$(RESET)"
@echo ""
./project5 < test-data/t01-nowhere.in > test-data/project5.out
diff test-data/project5.out test-data/t01-nowhere.out > test.diff
@echo "$(GREEN)Passed!$(RESET)"

# test the code against an expected output file
test-one-road: project5
@echo ""
@echo "$(RED)--- One Road Test ---$(RESET)"
@echo ""
./project5 < test-data/t02-one-road.in > test-data/project5.out
diff test-data/project5.out test-data/t02-one-road.out > test.diff
@echo "$(GREEN)Passed!$(RESET)"

# test the code against an expected output file
test-simple: project5
@echo ""
@echo "$(RED)--- Simple Test ---$(RESET)"
@echo ""
./project5 < test-data/t03-simple.in > test-data/project5.out
diff test-data/project5.out test-data/t03-simple.out > test.diff
@echo "$(GREEN)Passed!$(RESET)"

# test the code against an expected output file
test-local: project5
@echo ""
@echo "$(RED)--- Local Test ---$(RESET)"
@echo ""
./project5 < test-data/t08-local.in > test-data/project5.out
diff test-data/project5.out test-data/t08-local.out > test.diff
@echo "$(GREEN)Passed!$(RESET)"

# test the code against an expected output file
test-combo: project5
@echo ""
@echo "$(RED)--- Combo Test ---$(RESET)"
@echo ""
./project5 < test-data/t0502-combo.in > test-data/project5.out
diff test-data/project5.out test-data/t0502-combo.out > test.diff
@echo "$(GREEN)Passed!$(RESET)"
36 changes: 25 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
# cps222-2022-p5-opokunyarko-colbert

## Attempted:
* We attempted the following requirements:
* Reading and printing data
* Shortest paths
* The road upgrading goal
* Connected components analysis
* If bridges fail, isolated group is formed

## Unattempted:
* The following requirements were unattempted:
*
### Attempted & Status

- Requirement 1 : Read and print data

Town and road data can be correctly read and outputed to the terminal. Passes all tests with no diff issues and correct styling. Peer programmed.

- Requirement 2 : Shortest Paths

findShortestPath() method implemented to calculate shortest traversals and output them to the terminal. Passes all tests with no diff issues and correct stylings. Completed by Elijah Opoku-Nyarko with later revisions by Jake Colbert.

- Requirement 3 : Upgrading

minSpan() method implemented to find ideal connections for faster traversals and output recomendations to the terminal. Passes all tests with no diff issues and correct stylings. Completed by Elijah Opoku-Nyarko with later revisions by Jake Colbert.

- Requirement 4 : Worst-Case Analysis of Bridge Collapse

removeBridges() method implemented to find towns that would form isolated groups on bridge collapse. Passes all tests with some diff issues regarding ordering and correct stylings. Completed by Elijah Opoku-Nyarko with output revisions by Jake Colbert.

- Requirement 5 : Articulation Points

articulationPoints() method implemented to find points of the graph at which their destruction would disconnect the province graph. Does not pass tests. isAP[] array does not get modified by the recursive method and prints all zeros as it was initialized. In-Progress by Jake Colbert

### Makefile & Testing

A `make test-all` target has been implemented to return "Passed!" if no errors are caught when running other tests. On run, "--- <test name> ---" will be displayed to indicate which test was running upon crash. Any test error will likely result from differences in the project5.out file and the respective test.out file. View test.diff to see their differences.
Binary file modified project5
Binary file not shown.
4 changes: 3 additions & 1 deletion project5.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ int main(int argc, char *argv[]) {
theProvince.printAll(0, cout);
theProvince.printShortestPath(std::cout);
theProvince.minSpan(std::cout);
theProvince.removeBridges(cout);
theProvince.articulationPoints(cout);
std::cout << std::endl;
std::cout << "------------------------------------------------------------------";
std::cout << endl;
cout << endl << endl;
}
}
172 changes: 107 additions & 65 deletions province.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

using namespace std;

/*f
/*
* Constructor
* @param source File containing province:
* 1. One line: number of towns (n), number of roads (p)
Expand All @@ -32,48 +32,27 @@ Province::Province(std::istream & source) {

// Read town names
for (int i = 0; i < _numberOfTowns; i++) {
source >> _towns[i]._name; // This needs to be converted to vector, im not sure how exactly
//cout << "This is the name: " << &_towns[i]._name << endl;
source >> _towns[i]._name;
townMap[_towns[i]._name] = i;
}

// Read roads
for (int i = 0; i < _numberOfRoads; i++) {
std::string tail, head;
source >> tail >> head;
int tailIndex = townMap[tail]; // index of the first town
int headIndex = townMap[head]; // index of the second town

// Get the type of road ("B" If Bridge, "N" if normal road)
char type;
source >> type;
bool isBridge = (type == 'B');
// Not sure how to Get the type if it is a normal road (ie. Not a Bridge)

// Length of road
double length;
source >> length;

// Add a road to the road list
Road newRoad(headIndex, tailIndex, isBridge, length);
_roads.push_back(newRoad);

// Add a road to two connecting towns
_towns[tailIndex]._roads.push_back(Road(headIndex, tailIndex,
isBridge, length));
_towns[headIndex]._roads.push_back(Road(tailIndex, headIndex,
isBridge, length));


string tail, head;
char bridgeFlag;
double length;
source >> tail >> head >> bridgeFlag >> length;
bool isBridge = (bridgeFlag == 'B');
_roads.push_back(Road(townMap.at(head), townMap.at(tail), isBridge, length));
_towns[townMap.at(tail)]._roads.push_back(Road(townMap.at(head), townMap.at(tail), isBridge, length));
_towns[townMap.at(head)]._roads.push_back(Road(townMap.at(tail), townMap.at(head), isBridge, length));
}
}

void Province::printAll(int start, std::ostream & output) {
// keep track of whether a town(vertex) has been scheduled to be visited
bool scheduled[_numberOfTowns];
for (int i = 0; i < _numberOfTowns; i++){
scheduled[i] = false;
}
memset(scheduled, 0, sizeof scheduled); // initialize to 0/false

// Keep track of which towns have been visited
queue <int> toVisit; // use queue to keep track of which town to visit next
Expand Down Expand Up @@ -147,13 +126,6 @@ void Province::printShortestPath(std::ostream & output) const {
output << "The shortest paths from " + _towns[0]._name;
output << " are:" << std::endl << std::endl;

// keeps track of the index of the predecessor to each
// town(vertex) n on the shortest path to n
int prev[_numberOfTowns];

output << "The shortest routes from " + _towns[0]._name;
output << " are:" << std::endl << std::endl;

// keeps track of the index of the predecessor to each
// town(vertex) n on the shortest path to n
int prev[_numberOfTowns];
Expand Down Expand Up @@ -311,15 +283,18 @@ void Province::minSpan(std::ostream & output) const {
}
}

output << "The road upgrading goal can be achieved at minimal cost by upgrading:";
output << std::endl;

// Print names of towns in minimum spanning tree of province
for (int i = 0; i < minSpanTree.size(); i++) {
output << " ";
output << _towns[minSpanTree[i]._head]._name;
output << " to ";
output << _towns[minSpanTree[i]._tail]._name << std::endl;
output << "The road upgrading goal can be achieved at minimal cost by upgrading:";
output << std::endl;

// Print names of towns in minimum spanning tree of province
for (int i = 0; i < minSpanTree.size(); i++) {
output << " ";
output << _towns[minSpanTree[i]._head]._name;
output << " to ";
output << _towns[minSpanTree[i]._tail]._name << std::endl;
}
output << endl;
}

std::vector<int> Province::bfs(int start) const {
// Initialize list of towns scheduled to visit
Expand Down Expand Up @@ -374,26 +349,14 @@ void Province::removeBridges(ostream &output) const {
break;
}
}
// If only one town
if (_numberOfTowns == 1) {
output << "There is only one town, so the province "
<< "will not be affected by a major storm";
return;

// If province has no bridge
} else if (!hasBridge) {
output << "The province has no bridges, so it "
<< "will not be affected by a major storm";
return;
}

// Mark all towns as unvisited
list<int> toVisit;
for (int i = 0; i < _numberOfTowns; i++) {
toVisit.push_back(i);
}
output << "Connected components in event of a major storm are: ";
output << endl << endl;
output << "Connected components in event of a major storm are:";
output << endl;

while (!toVisit.empty()) {
// Mark current town as visited
Expand All @@ -408,16 +371,95 @@ void Province::removeBridges(ostream &output) const {
toVisit.remove(bfsResult[i]);
}

output << " ";
output << " ";
output << "If all bridges fail, the following towns would form ";
output << "an isolated group:" << endl;

// Print names of all towns in connected component
for (int i = 0; i < bfsResult.size(); i++) {
output << " ";
output << " ";
output << _towns[bfsResult[i]]._name << endl;
}
output << endl;
}

}

void Province::APUtil(int u, bool visited[],
int disc[], int low[], int& time, int parent,
bool isAP[]) const {
// Count of children in DFS Tree
int children = 0;

// Mark the current node as visited
visited[u] = true;

// Initialize discovery time and low value
disc[u] = low[u] = ++time;

// Go through all vertices adjacent to this
for (int v = 0; v < _numberOfTowns; v++) {
// If v is not visited yet, then make it a child of u
// in DFS tree and recur for it
if (!visited[v]) {
children++;
APUtil(v, visited, disc, low, time, u, isAP);

// Check if the subtree rooted with v has
// a connection to one of the ancestors of u
low[u] = min(low[u], low[v]);

// If u is not root and low value of one of
// its child is more than discovery value of u.
if (parent != -1 && low[v] >= disc[u]) {
isAP[u] = true;
}
} else if (v != parent) {
low[u] = min(low[u], disc[v]);
}
}

// If u is root of DFS tree and has two or more children.
if (parent == -1 && children > 1) {
isAP[u] = true;
}
}

void Province::articulationPoints(std::ostream & output) const
{
int disc[_numberOfTowns];
memset(disc, 0, sizeof disc);
int low[_numberOfTowns];
bool visited[_numberOfTowns];
memset(visited, false, sizeof visited);
bool isAP[_numberOfTowns];
memset(isAP, false, sizeof isAP);
int time = 0, par = -1;

// Adding this loop so that the
// code works even if we are given
// disconnected graph
for (int u = 0; u < _numberOfTowns; u++) {
if (!visited[u]) {
APUtil(u, visited, disc, low,
time, par, isAP);
}
}
output << "Destruction of any of the following would result in the province becoming" << endl << "disconnected:" << endl;

int count = 0;
// Printing the APs
for (int u = 0; u < _numberOfTowns; u++) {
if (isAP[u] == true) {
output << " " << _towns[u]._name << endl;
count++;
}
}
if (count == 0) {
output << " (None)" << endl;
}
output << endl;

for (bool i : isAP) {
cerr << i << endl;
}
}
4 changes: 4 additions & 0 deletions province.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ class Province
* @return - List of indices of towns in order of traversal
*/
std::vector<int> bfs(int start) const;

void APUtil(int u, bool visited[],
int disc[], int low[], int& time, int parent,
bool isAP[]) const;

void dfsAux(int current, std::vector<int> & dfsTowns, bool visited []) const;

Expand Down
Loading

0 comments on commit 2b3b759

Please sign in to comment.