Cod sursa(job #1665501)

Utilizator StanescuVictorStanescu Victor Laurentiu StanescuVictor Data 26 martie 2016 23:59:15
Problema Componente biconexe Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 18.84 kb
#include <iostream>
#include <fstream>
#include <conio.h>
#include <vector>
#include <stack>
#include <queue>
#include <list>

typedef unsigned int uint;

class Graph
{
public:
	virtual ~Graph() { }

	uint getVertices() const { return vertices; }
	uint getEdges() const { return edges; }

	virtual uint getDegree(uint vertex) const = 0;
	virtual uint getMinDegree() const = 0;
	virtual uint getMaxDegree() const = 0;

	virtual double getDensity() const = 0;

	virtual bool isComplete() const = 0;
	virtual bool isRegular() const = 0;

	virtual std::vector<uint> breadthFirstSearch(uint vertex) const = 0;
	virtual std::vector<uint> depthFirstSearch(uint vertex) const = 0;

	virtual std::vector<std::vector<bool>> getRoadMatrix() const = 0;
	virtual std::vector<int> getRoadDistance(uint vertex) const = 0;

	friend std::ostream& operator<<(std::ostream& os, const Graph& graph);
	friend std::ofstream& operator<<(std::ofstream& ofs, const Graph& graph);

protected:
	std::vector<std::vector<uint>> adjacencyList;
	uint vertices, edges;

	Graph() : vertices(0), edges(0), adjacencyList(0) { }
	Graph(uint _vertices, uint _edges, std::vector<std::vector<uint>> _adjacencyList) :
		vertices(_vertices), edges(_edges), adjacencyList(_adjacencyList) { }

	bool isValidVertex(uint vertex) const;
};

bool Graph::isValidVertex(uint vertex) const
{
	if (vertex < 0 || vertex > vertices - 1)
		return false;

	return true;
}

std::ostream& operator<<(std::ostream& os, const Graph& graph)
{
	for (uint i = 0; i < graph.adjacencyList.size(); i++)
	{
		os << i << " | ";
		for (uint j = 0; j < graph.adjacencyList[i].size(); j++)
			os << graph.adjacencyList[i][j] << " ";
		os << "\n";
	}

	return os;
}

std::ofstream& operator<<(std::ofstream& ofs, const Graph& graph)
{
	for (uint i = 0; i < graph.adjacencyList.size(); i++)
	{
		ofs << i << " | ";
		for (uint j = 0; j < graph.adjacencyList[i].size(); j++)
			ofs << graph.adjacencyList[i][j] << " ";
		ofs << "\n";
	}

	return ofs;
}

class UndirectedGraph : public Graph
{
public:
	UndirectedGraph() : Graph() { }
	UndirectedGraph(std::ifstream& ifs);
	UndirectedGraph(const UndirectedGraph& source) : Graph(source.vertices, source.edges, source.adjacencyList) { }
	~UndirectedGraph() { };

	uint getDegree(uint vertex) const;
	uint getMinDegree() const;
	uint getMaxDegree() const;

	double getDensity() const { return ((2 * (double)edges) / (double)(vertices * (vertices - 1))); }

	bool isComplete() const;
	bool isRegular() const;
	bool isConnected() const;
	bool isHamiltonian() const;
	bool isEulerian() const;
	bool isBipartite() const;
	bool isBiconnected() const;

	std::vector<uint> breadthFirstSearch(uint vertex) const;
	std::vector<uint> depthFirstSearch(uint vertex) const;

	std::vector<std::vector<bool>> getRoadMatrix() const;
	std::vector<int> getRoadDistance(uint vertex) const;

	std::vector<std::vector<uint>> getConnectedComponents() const;
	std::vector<std::vector<uint>> getBiconnectedComponents() const;
	std::vector<uint> getArticulationPoints() const;

	UndirectedGraph& operator=(const UndirectedGraph& source);

	UndirectedGraph operator+(const UndirectedGraph& source);
	UndirectedGraph operator-(const UndirectedGraph& source);

	bool operator==(const UndirectedGraph& source);
	bool operator!=(const UndirectedGraph& source) { return !((*this) == source); }

	friend std::istream& operator>>(std::istream& is, UndirectedGraph& graph);
	friend std::ifstream& operator>>(std::ifstream& ifs, UndirectedGraph& graph);

private:
	void articulationPoint(uint vertex, std::vector<bool>& visited, std::vector<int>& parent,
		std::vector<uint>& discoveryTime, std::vector<uint>& low, std::vector<uint>& articulationPoints) const;

	bool hasArticulationPoint(uint vertex, std::vector<bool>& visited, std::vector<int>& parent,
		std::vector<uint>& discoveryTime, std::vector<uint>& low) const;

	void getBiconnectedComponents(uint vertex, std::vector<int>& parent, std::vector<uint>& depth,
		std::vector<uint>& low, std::stack<uint>& stack, std::vector<std::vector<uint>>& biconnectedComponents) const;
};

// -- Public methods

UndirectedGraph::UndirectedGraph(std::ifstream& ifs)
{
	ifs >> vertices >> edges;
	adjacencyList.resize(vertices);

	for (uint i = 0; i < edges; i++)
	{
		uint x, y;
		ifs >> x >> y;
		x--; y--;
		adjacencyList[x].push_back(y);
		adjacencyList[y].push_back(x);
	}
}

uint UndirectedGraph::getDegree(uint vertex) const
{
	if (!isValidVertex(vertex))
		return 0;

	return adjacencyList[vertex].size();
}

uint UndirectedGraph::getMinDegree() const
{
	if (!vertices || vertices == 1 || !edges)
		return 0;

	uint minDegree = getDegree(0);

	for (unsigned int i = 1; i < vertices; i++)
		if (getDegree(i) < minDegree)
			minDegree = getDegree(i);

	return minDegree;
}

uint UndirectedGraph::getMaxDegree() const
{
	if (!vertices || vertices == 1 || !edges)
		return 0;

	uint maxDegree = getDegree(0);

	for (uint i = 1; i < vertices; i++)
		if (getDegree(i) > maxDegree)
			maxDegree = getDegree(i);

	return maxDegree;
}

bool UndirectedGraph::isComplete() const
{
	if ((vertices * (vertices - 1)) / 2 == edges)
		return true;

	return false;
}

bool UndirectedGraph::isRegular() const
{
	for (uint i = 1; i < vertices; i++)
		if (getDegree(i) != getDegree(i - 1))
			return false;

	return true;
}

bool UndirectedGraph::isConnected() const
{
	if (!vertices)
		return false;

	if (vertices == 1)
		return true;

	if (!edges)
		return false;

	if (getConnectedComponents().size() == 1)
		return true;

	return false;
}

bool UndirectedGraph::isHamiltonian() const
{
	if (vertices < 3)
		return false;

	if (isComplete())
		return true;

	for (uint i = 0; i < vertices; i++)
		if (getDegree(i) < vertices / 2)
			return false;

	return true;
}

bool UndirectedGraph::isEulerian() const
{
	if (!isConnected())
		return false;

	for (uint i = 0; i < vertices; i++)
		if (getDegree(i) % 2 != 0)
			return false;

	return true;
}

bool UndirectedGraph::isBipartite() const
{
	if (!vertices || !edges)
		return false;

	std::vector<bool> visited(vertices);
	std::vector<char> color(vertices);
	std::queue<uint> queue;

	queue.push(0);
	visited[0] = true;
	color[0] = 0;

	while (!queue.empty())
	{
		uint element = queue.front();

		for (uint i = 0; i < getDegree(element); i++)
			if (!visited[adjacencyList[element][i]])
			{
				queue.push(adjacencyList[element][i]);
				visited[adjacencyList[element][i]] = true;
				color[adjacencyList[element][i]] = (color[element] == 0 ? 1 : 0);
			}
			else if (color[element] == color[adjacencyList[element][i]])
				return false;

		queue.pop();
	}

	return true;
}

bool UndirectedGraph::isBiconnected() const
{
	if (!vertices || !edges)
		return false;

	std::vector<bool> visited(vertices, false);
	std::vector<int> parent(vertices, -1);
	std::vector<uint> discoveryTime(vertices);
	std::vector<uint> low(vertices);

	// Check if the graph has at least one articulation point
	if (hasArticulationPoint(0, visited, parent, discoveryTime, low))
		return false;

	// Check if the graph is connected
	for (uint i = 0; i < visited.size(); i++)
		if (!visited[i])
			return false;

	return true;
}

std::vector<uint> UndirectedGraph::breadthFirstSearch(uint vertex) const
{
	if (!isValidVertex(vertex))
		return std::vector<uint>();

	std::vector<bool> visited(vertices);
	std::queue<uint> queue;
	std::vector<uint> connectedComponent;

	queue.push(vertex);
	visited[vertex] = true;
	connectedComponent.push_back(vertex);

	while (!queue.empty())
	{
		uint element = queue.front();

		for (uint i = 0; i < getDegree(element); i++)
			if (!visited[adjacencyList[element][i]])
			{
				connectedComponent.push_back(adjacencyList[element][i]);
				queue.push(adjacencyList[element][i]);
				visited[adjacencyList[element][i]] = true;
			}
		queue.pop();
	}

	return connectedComponent;
}

std::vector<uint> UndirectedGraph::depthFirstSearch(uint vertex) const
{
	if (!isValidVertex(vertex))
		return std::vector<uint>();

	std::vector<bool> visited(vertices);
	std::stack<uint> stack;
	std::vector<uint> connectedComponent;

	stack.push(vertex);
	visited[vertex] = true;
	connectedComponent.push_back(vertex);

	while (!stack.empty())
	{
		uint index, element = stack.top();
		bool found = false;

		for (index = 0; index < getDegree(element) && !found; index++)
			if (!visited[adjacencyList[element][index]])
				found = true;

		if (found)
		{
			index--;
			stack.push(adjacencyList[element][index]);
			visited[adjacencyList[element][index]] = true;
			connectedComponent.push_back(adjacencyList[element][index]);
		}
		else
			stack.pop();
	}

	return connectedComponent;
}

std::vector<std::vector<bool>> UndirectedGraph::getRoadMatrix() const
{
	std::vector<std::vector<bool>> roadMatrix(vertices);
	std::vector<std::vector<uint>> connectedComponents = getConnectedComponents();

	for (uint i = 0; i < roadMatrix.size(); i++)
		roadMatrix[i].resize(vertices, false);

	for (uint i = 0; i < connectedComponents.size(); i++)
		for (uint j = 0; j < connectedComponents[i].size() - 1; j++)
			for (uint k = j + 1; k < connectedComponents[i].size(); k++)
			{
				roadMatrix[connectedComponents[i][j]][connectedComponents[i][k]] = true;
				roadMatrix[connectedComponents[i][k]][connectedComponents[i][j]] = true;
			}

	return roadMatrix;
}

std::vector<int> UndirectedGraph::getRoadDistance(uint vertex) const
{
	if (!isValidVertex(vertex))
		return std::vector<int>();

	std::vector<bool> visited(vertices);
	std::queue<uint> queue;
	std::vector<int> roadDistance(vertices, -1);

	queue.push(vertex);
	visited[vertex] = true;
	roadDistance[vertex] = 0;

	while (!queue.empty())
	{
		uint element = queue.front();

		for (uint i = 0; i < getDegree(element); i++)
			if (!visited[adjacencyList[element][i]])
			{
				roadDistance[adjacencyList[element][i]] = roadDistance[element] + 1;
				queue.push(adjacencyList[element][i]);
				visited[adjacencyList[element][i]] = true;
			}
		queue.pop();
	}

	return roadDistance;
}

std::vector<std::vector<uint>> UndirectedGraph::getConnectedComponents() const
{
	std::vector<std::vector<uint>> connectedComponents;
	std::vector<bool> visited(vertices, false);

	for (uint i = 0; i < vertices; i++)
	{
		if (!visited[i])
		{
			connectedComponents.push_back(depthFirstSearch(i));

			for (uint j = 0; j < connectedComponents.back().size(); j++)
				visited[connectedComponents.back()[j]] = true;
		}
	}

	return connectedComponents;
}

std::vector<std::vector<uint>> UndirectedGraph::getBiconnectedComponents() const
{
	std::stack<uint> stack;
	std::vector<int> parent(vertices, -1);					// Represents the parent of the vertex in DFS-tree.
	std::vector<uint> low(vertices, 0);						// Represents the lowest depth of a vertex connected to the index vertex through a back-edge in DFS-tree.
	std::vector<uint> depth(vertices, 0);					// Represents the depth of the vertex in DFS-tree.
	std::vector<std::vector<uint>> biconnectedComponents;

	for (uint vertex = 0; vertex < vertices; vertex++)
		if (!depth[vertex])
			getBiconnectedComponents(vertex, parent, depth, low, stack, biconnectedComponents);

	return biconnectedComponents;
}

std::vector<uint> UndirectedGraph::getArticulationPoints() const
{
	std::vector<bool> visited(vertices, false);
	std::vector<int> parent(vertices, -1);
	std::vector<uint> discoveryTime(vertices);
	std::vector<uint> low(vertices);
	std::vector<uint> articulationPoints;

	for (uint i = 0; i < vertices; i++)
		if (!visited[i])
			articulationPoint(i, visited, parent, discoveryTime, low, articulationPoints);

	return articulationPoints;
}

// -- End of Public methods

// -- Private methods

void UndirectedGraph::articulationPoint(uint vertex, std::vector<bool>& visited, std::vector<int>& parent,
	std::vector<uint>& discoveryTime, std::vector<uint>& low, std::vector<uint>& articulationPoints) const
{
	if (!isValidVertex(vertex))
		return;

	static uint time = 0;
	uint children = 0;
	visited[vertex] = true;
	discoveryTime[vertex] = low[vertex] = ++time;

	for (uint i = 0; i < adjacencyList[vertex].size(); i++)
	{
		if (!visited[adjacencyList[vertex][i]])
		{
			children++;
			parent[adjacencyList[vertex][i]] = vertex;
			articulationPoint(adjacencyList[vertex][i], visited, parent, discoveryTime, low, articulationPoints);

			if (low[adjacencyList[vertex][i]] < low[vertex])
				low[vertex] = low[adjacencyList[vertex][i]];

			if ((parent[vertex] == -1 && children > 1) || (parent[vertex] != -1 && low[adjacencyList[vertex][i]] >= discoveryTime[vertex]))
				articulationPoints.push_back(vertex);
		}
		else if ((adjacencyList[vertex][i] != parent[vertex]) && (discoveryTime[adjacencyList[vertex][i]] < low[vertex]))
			low[vertex] = discoveryTime[adjacencyList[vertex][i]];
	}
}

// Same as articulationPoint, just we don't need all articulation points to check if a graph is biconnected.
bool UndirectedGraph::hasArticulationPoint(uint vertex, std::vector<bool>& visited, std::vector<int>& parent,
	std::vector<uint>& discoveryTime, std::vector<uint>& low) const
{
	if (!isValidVertex(vertex))
		return false;

	static uint time = 0;
	uint children = 0;
	visited[vertex] = true;
	discoveryTime[vertex] = low[vertex] = ++time;

	for (uint i = 0; i < adjacencyList[vertex].size(); i++)
	{
		if (!visited[adjacencyList[vertex][i]])
		{
			children++;
			parent[adjacencyList[vertex][i]] = vertex;

			if (hasArticulationPoint(adjacencyList[vertex][i], visited, parent, discoveryTime, low))
				return true;

			if (low[adjacencyList[vertex][i]] < low[vertex])
				low[vertex] = low[adjacencyList[vertex][i]];

			if ((parent[vertex] == -1 && children > 1) ||
				(parent[vertex] != -1 && low[adjacencyList[vertex][i]] >= discoveryTime[vertex]))
				return true;
		}
		else if ((adjacencyList[vertex][i] != parent[vertex]) &&
			(discoveryTime[adjacencyList[vertex][i]] < low[vertex]))
			low[vertex] = discoveryTime[adjacencyList[vertex][i]];
	}

	return false;
}

void UndirectedGraph::getBiconnectedComponents(uint vertex, std::vector<int>& parent, std::vector<uint>& depth,
	std::vector<uint>& low, std::stack<uint>& stack, std::vector<std::vector<uint>>& biconnectedComponents) const
{
	if (!isValidVertex(vertex))
		return;

	static uint currentDepth = 0;
	stack.push(vertex);
	depth[vertex] = low[vertex] = ++currentDepth;

	for (std::vector<uint>::const_iterator neighbour = adjacencyList[vertex].begin(); neighbour != adjacencyList[vertex].end(); neighbour++)
	{
		if (!depth[*neighbour])
		{
			parent[*neighbour] = vertex;
			getBiconnectedComponents(*neighbour, parent, depth, low, stack, biconnectedComponents);
			low[vertex] = std::min(low[vertex], low[*neighbour]);

			// Check if vertex is an articulation point.
			if (low[*neighbour] >= depth[vertex])
			{
				biconnectedComponents.push_back(std::vector<uint>());
				std::vector<std::vector<uint>>::reverse_iterator iterator = biconnectedComponents.rbegin();
				while (stack.top() != *neighbour)
				{
					iterator->push_back(stack.top());
					stack.pop();
				}
				iterator->push_back(*neighbour);
				stack.pop();
				iterator->push_back(vertex);
			}
		}
		// Check if neighbour is an ancestor of vertex in dfs tree.
		else if (*neighbour != parent[vertex])
			low[vertex] = std::min(low[vertex], depth[*neighbour]);
	}
}

// -- End of Private methods

// -- Overloaded Operators

UndirectedGraph& UndirectedGraph::operator=(const UndirectedGraph& source)
{
	if (this == &source)
		return *this;

	vertices = source.vertices;
	edges = source.edges;
	adjacencyList = source.adjacencyList;

	return *this;
}

UndirectedGraph UndirectedGraph::operator+(const UndirectedGraph& source)
{
	// TODO: better way to handle this
	if (this->vertices != source.vertices || this->vertices == 0)
		return UndirectedGraph();

	UndirectedGraph sumGraph;
	sumGraph.vertices = this->vertices;
	sumGraph.adjacencyList.resize(sumGraph.vertices);

	for (uint i = 0; i < sumGraph.vertices; i++)
	{
		for (uint j = 0; j < this->adjacencyList[i].size(); j++)
			sumGraph.adjacencyList[i].push_back(this->adjacencyList[i][j]);

		for (uint j = 0; j < source.adjacencyList[i].size(); j++)
		{
			bool found = false;

			for (uint k = 0; k < sumGraph.adjacencyList[i].size(); k++)
				if (sumGraph.adjacencyList[i][k] == source.adjacencyList[i][j])
					found = true;

			if (!found)
				sumGraph.adjacencyList[i].push_back(source.adjacencyList[i][j]);
		}
	}

	return sumGraph;
}

UndirectedGraph UndirectedGraph::operator-(const UndirectedGraph& source)
{
	// TODO: better way to handle this
	if (this->vertices != source.vertices || this->vertices == 0)
		return UndirectedGraph();

	UndirectedGraph difGraph;
	difGraph.vertices = this->vertices;
	difGraph.adjacencyList.resize(difGraph.vertices);

	for (uint i = 0; i < this->adjacencyList.size(); i++)
	{
		for (uint j = 0; j < this->adjacencyList[i].size(); j++)
		{
			bool found = false;
			for (uint k = 0; k < source.adjacencyList[i].size(); k++)
				if (this->adjacencyList[i][j] == source.adjacencyList[i][k])
					found = true;

			if (!found)
				difGraph.adjacencyList[i].push_back(this->adjacencyList[i][j]);
		}
	}

	return difGraph;
}

bool UndirectedGraph::operator==(const UndirectedGraph& source)
{
	if (this->vertices != source.vertices || this->edges != source.edges || this->adjacencyList != source.adjacencyList)
		return false;

	if (((*this) + source).edges != this->edges)
		return false;

	return true;
}

// -- End of Overloaded Operators

// -- Friend methods/operators

std::istream& operator>>(std::istream& is, UndirectedGraph& graph)
{
	is >> graph.vertices >> graph.edges;
	graph.adjacencyList.resize(graph.vertices);

	for (uint i = 0; i < graph.edges; i++)
	{
		uint x, y;
		is >> x >> y;
		x--; y--;
		graph.adjacencyList[x].push_back(y);
		graph.adjacencyList[y].push_back(x);
	}

	return is;
}

std::ifstream& operator>>(std::ifstream& ifs, UndirectedGraph& graph)
{
	ifs >> graph.vertices >> graph.edges;
	graph.adjacencyList.resize(graph.vertices);

	for (uint i = 0; i < graph.edges; i++)
	{
		uint x, y;
		ifs >> x >> y;
		x--; y--;
		graph.adjacencyList[x].push_back(y);
		graph.adjacencyList[y].push_back(x);
	}

	return ifs;
}

// -- End of Friend methods/operators

int main()
{
	std::ifstream f("biconex.in");
	std::ofstream g("biconex.out");
	UndirectedGraph graph(f);

	std::vector<std::vector<uint>> biconnectedComponents = graph.getBiconnectedComponents();
	g << biconnectedComponents.size() << "\n";
	for (uint i = 0; i < biconnectedComponents.size(); i++)
	{
		for (uint j = 0; j < biconnectedComponents[i].size(); j++)
			g << biconnectedComponents[i][j]+1 << " ";
		g << "\n";
	}

	return 0;
}