Cod sursa(job #459618)

Utilizator tomescu_alinTomescu Alin tomescu_alin Data 30 mai 2010 14:03:14
Problema Componente tare conexe Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.57 kb
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <iostream>
#include <fstream>

using namespace std;

typedef unsigned int uint;

/**
 *	A normal stack class that can check in constant time if a
 *	certain element is contained within the stack.
 */
class Stack
{
	public:
		Stack(uint maxSize)
		{
			stack.reserve(maxSize + 1);
			isInStack.resize(maxSize + 1, false);
		}
	
	public:
		void push(uint node)
		{
			stack.push_back(node);
			isInStack[node] = true;
		}
		
		uint peek() const { return stack.back(); }
		
		uint pop()
		{
			uint node = stack.back();
			
			stack.pop_back();
			
			isInStack[node] = false;
			
			return node;
		}
		
		bool isEmpty() const { return stack.empty(); }
		
		bool contains(uint node) { return isInStack[node]; }
	
	private:
		std::vector<bool> isInStack;
		std::vector<uint> stack;
};

/**
 *	More like a "half" edge.
 */
class Edge
{
	public:
		Edge(uint destNode)
			:	dest(destNode), next(0)
		{}
	
	public:
		uint dest;
		Edge * next;
};

/**
 *	Class used to represent/store a directed graph using an
 *	adjacency list.
 */
class AdjacencyList
{
	public:
		AdjacencyList(uint nodes)
			:	numNodes(nodes)
		{
			list.resize(nodes + 1, NULL);
		}
		
		~AdjacencyList()
		{
			for(uint i = 0; i < list.size(); i++)
			{
				if(list[i])
				{
					Edge * current = list[i];
					while(current)
					{
						Edge * deleted = current;
						current = current->next;
						
						delete deleted;
					}
				}
			}
		}
		
	public:
		void insertEdge(uint src, uint dest)
		{
			if(!list[src])
			{
				list[src] = new Edge(dest);
			}
			else
			{
				Edge * e = new Edge(dest);
				e->next = list[src];
				list[src] = e;
			}
		}
		
		Edge * getEdges(uint node) { return list[node]; }
		
		void print()
		{
			for(uint i = 0; i < list.size(); i++)
			{
				if(list[i])
				{
					Edge * e = list[i];
					while(e)
					{
						cout << "(" << i << ", " << e->dest << ")" << endl;
						e = e->next;
					}
				}
			}
		}
		
	private:
		std::vector<Edge *> list;
		uint numNodes;
};

struct Component
{
	Component() : next(0) {}
	
	std::vector<uint> nodes;
	Component * next;
};

/**
 *	A class used to determine the strongly connected components of a directed
 *	graph.
 */
class StronglyConnectedComponents
{
	public:
		StronglyConnectedComponents(
			AdjacencyList& initGraph,
			AdjacencyList& transGraph,
			Stack& stack,
			uint nodes
		)
			:	graph(initGraph), transposeGraph(transGraph),
				nodeStack(stack), numNodes(nodes), numComponents(0)
		{
			visited.resize(nodes + 1, false);
			whichComp.resize(nodes + 1, 0);
		}
		
	public:
		void execute()
		{
			firstDfs();
			secondDfs();
		}
		
		std::vector<uint> * getComponents() { return components; }
		uint getNumComponents() { return numComponents; }
	
	private:
		/**
		 *	The first depth first search just goes through the graph
		 *	and creates a stack of all the nodes, such that the node 
		 *	at the top of the stack is the node with the maximum finishing
		 *	time.
		 */
		void firstDfs()
		{
			for(uint node = 1; node <= numNodes; node++)
			{
				if(!visited[node])
					firstDfsRecursive(node);
			}
		}
		
		void firstDfsRecursive(uint node = 1)
		{
			visited[node] = true;
			
			for(Edge * edge = graph.getEdges(node);
				edge != 0; 
				edge = edge->next)
			{
				if(!visited[edge->dest])
					firstDfsRecursive(edge->dest);
			}
			
			nodeStack.push(node);
		}
		
		void secondDfs()
		{
			while(!nodeStack.isEmpty())
			{
				numComponents++;
				
				secondDfsRecursive(nodeStack.peek());
				
				while(!nodeStack.isEmpty() && whichComp[nodeStack.peek()] != 0)
					nodeStack.pop();
			}
			
			components = new std::vector<uint>[numComponents];
			
			for(uint i = 1; i <= numNodes; i++)
			{
				components[whichComp[i] - 1].push_back(i);
			}
		}
		
		void secondDfsRecursive(uint node)
		{
			/**
			 *	In this case we think of the visited vector as representing
			 *	a "not-visited" vector. This way we save the space and hassle
			 *	of creating another visited vector for the second search.
			 */
			visited[node] = false;
			whichComp[node] = numComponents;
			
			for(Edge * edge = transposeGraph.getEdges(node);
				edge != 0; 
				edge = edge->next)
			{
				if(visited[edge->dest])
					secondDfsRecursive(edge->dest);
			}
			
			
		}
	
	private:
		AdjacencyList& graph;
		AdjacencyList& transposeGraph;
		Stack& nodeStack;
		uint numNodes;
		uint numComponents;
		std::vector<bool> visited;
		std::vector<uint> whichComp;
		std::vector<uint> * components;
};

int main()
{
	const char * inFile = "ctc.in";
	const char * outFile = "ctc.out";
	
	ifstream fin(inFile);
	
	uint numNodes, numEdges;
	fin >> numNodes >> numEdges;
	
	AdjacencyList graph(numNodes);
	AdjacencyList transposeGraph(numNodes);
	Stack nodeStack(numNodes);
	
	for(uint i = 0; i < numEdges; i++)
	{
		uint x, y;
		fin >> x >> y;
		
		graph.insertEdge(x, y);
		transposeGraph.insertEdge(y, x);
	}
	
	fin.close();
	
	StronglyConnectedComponents scc(graph, transposeGraph, nodeStack, numNodes);
	scc.execute();
	
	ofstream fout(outFile);
	
	uint numComponents = scc.getNumComponents();
	fout << numComponents << "\n";
	
	std::vector<uint> * component = scc.getComponents();
	
	for(uint i = 0; i < numComponents; i++)
	{
		for(uint j = 0; j < component[i].size(); j++)
		{
			fout << component[i][j] << " ";
		}
		fout << "\n";
	}
	
	fout.close();
	
	return 0;
}