Reputation: 10784
I am making a problem of ACM competitions to determine the number of connected components that have an undirected graph G and vertices belonging to each component. 've Already done with a DFS algorithm, counting the number of connected components of undirected graph (the hard part of problem), but I can not think of anything to indicate the nodes belonging to each component or have a record of the nodes.
Input: The first line of input will an integer C, which indicates the number of test cases. The first line of each test case contains two integers N and E, where N represents the number of nodes in the graph and E the number of edges in it. Then follow E lines, each with 2 integers I and J, where I and J represent the existence of an edge between node I and node J (0 ≤ I, J
Output: In the first line of each test case must display the following string "Case G: P component (s) connected (s)", where G represents the number of test case (starting at 1) and P the number of components connected in the graph. Then X lines, each containing the nodes belonging to a connected component (in order from smallest to largest) separated by spaces. After each test case should print a blank line. The output should be written in the "output.out."
Example:
Input:
2
6 9
0 1
0 2
1 2
5 4
3 1
2 4
2 5
3 4
3 5
8 7
0 1
2 1
2 0
3 4
4 5
5 3
7 6
Output:
Case 1: 1 component (s) connected (s)
0 1 2 3 4 5
Case 2: 3 component (s) connected (s)
0 1 2
3 4 5
6 7
Here's my code:
#include <stdio.h>
#include <vector>
#include <stdlib.h>
#include <string.h>
using namespace std;
vector<int> adjacency[10000];
bool visited[10000];
/// @param Standard algorithm DFS
void dfs(int u){
visited[ u ] = true;
for( int v = 0 ; v < adjacency[u].size(); ++v ){
if( !visited[ adjacency[u][v] ] ){
dfs( adjacency[u][v] );
}
}
}
int main(int argc, char *argv []){
#ifndef ONLINE_JUDGE
#pragma warning(disable: 4996)
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
///enumerate vertices from 1 to vertex
int vertex, edges , originNode ,destinationNode, i, j,cont =1;
///number of test cases
int testCases;
int totalComponents;
scanf ("%d", &testCases);
for (i=0; i<testCases; i++){
memset( visited , 0 , sizeof( visited ) );
scanf("%d %d" , &vertex , &edges );
for (j=0; j<edges; j++){
scanf("%d %d" , &originNode ,&destinationNode );
adjacency[ originNode ].push_back( destinationNode );
adjacency[ destinationNode ].push_back( originNode );
}
totalComponents =0;
for( int i = 0 ; i < vertex ; ++i ){ // Loop through all possible vertex
if( !visited[ i ] ){ //if we have not visited any one component from that node
dfs( i ); //we travel from node i the entire graph is formed
totalComponents++; //increased amount of components
}
}
printf("Case %d: %d component (s) connected (s)\n" ,cont++, totalComponents);
for (j=0;j<total;j++){
/*here should indicate the vertices of each connected component*/
}
memset( adjacency , 0 , sizeof( adjacency ) );
}
return 0;
}
I have doubts about how to carry memory of the nodes belonging to each connected component or structure should be used to store, how I should modify my code to do this?, I would like to hear suggestions, ideas or any implementation in pseudocode. Thanks to all
Upvotes: 5
Views: 7892
Reputation: 5681
General algorithm to test if 2 nodes are connected:
At first your nodes will be each in its set,
o o1 o o o o o o2
\ / \ / \ / \ /
o o o o o o o o
\ / \ /
o o o o o o o o
\ /
o o1 o o o o o o2
As the algorithm progresses and merges the sets, it relatively halves the input.
In the example above I was looking to see if there was a path between o1 and o2. I found this path only at the end after merging all edges. Some graphs may have separate components (disconnected) which entails that you will not be able to have one set at the end. In such a case you can use this algorithm to test for connectedness and even count the number of components in a graph. The number of components is the number of sets you are able to get when the algorithm finishes.
A possible graph (for the tree above):
o-o1-o-o-o2
| |
o o
|
o
Upvotes: 0
Reputation: 10784
the solution is much easier, you must declare two arrays of size the number of vertices
int vertexNodes [vertex] / / / array to store the nodes
int vertexComponents [vertex] / / / array to store the number of components
Then, when you call to DFS each vertex is stored in the array of vertices, and stored at that component belongs
for( int i = 0 ; i < vertex ; ++i ) //iterate on all vertices
{
vertexNodes [i]=i; //fill the array with the vertices of the graph
if( !visited[ i ] )
{ ///If any node is visited DFS call
dfs(i);
totalComponents++; ///increment number of components
}
vertexComponents [i]=totalComponents; ///is stored at each node component belongs to
}
Finally, it prints the total components and created a flag with the value of the first component which is compared with the component of each vertex
printf("Case %d: %d component (s) connected (s)\n" ,cont++, totalComponents);
int flag = vertexComponents[0]; ///Create a flag with the value of the first component
for (k=0; k <totalComponents; ++k) ///do a cycle length of the number of components
{
if (flag == vertexComponents [k] ) ///check if the vertex belongs to the first component
{
printf ("%d ", vertexComponents[k]); ///print on the same line as belonging to the same component
}else {
printf ("\n"); ///else we make newline and update the flag to the next component
flag = vertexComponents[k];
printf ("%d ", vertexComponents[k]);///and print the vertices of the new connected component
}
}
Upvotes: 1
Reputation: 52107
The algorithm is roughly:
The result is a set of "component" data structures (std::vector
s in my implementation), each containing a set of exclusively inter-connected nodes.
Considerations:
std::vector
.Here is the working code. Note that some C++11 features were used, but they should be easy to replace if older compiler is used. The error handling is left as exercise for the reader.
#include <iostream>
#include <vector>
#include <algorithm>
// A set of inter-connected nodes.
typedef std::vector<unsigned> Component;
// Graph node.
struct Node {
Node() : Traversed(false) {
}
std::vector<unsigned> Children;
std::vector<unsigned> Parents;
bool Traversed;
};
// Recursive portion of the FindGraphComponents implementation.
// graph: The graph constructed in FindGraphComponents().
// node_id: The index of the current element of graph.
// component: Will receive nodes that comprise the current component.
static void FindConnectedNodes(std::vector<Node>& graph, unsigned node_id, Component& component) {
Node& node = graph[node_id];
if (!node.Traversed) {
node.Traversed = true;
component.push_back(node_id);
for (auto i = node.Children.begin(); i != node.Children.end(); ++i)
FindConnectedNodes(graph, *i, component);
for (auto i = node.Parents.begin(); i != node.Parents.end(); ++i)
FindConnectedNodes(graph, *i, component);
}
}
// Finds self-connected sub-graphs (i.e. "components") on already-prepared graph.
std::vector<Component> FindGraphComponents(std::vector<Node>& graph) {
std::vector<Component> components;
for (unsigned node_id = 0; node_id < graph.size(); ++node_id) {
if (!graph[node_id].Traversed) {
components.push_back(Component());
FindConnectedNodes(graph, node_id, components.back());
}
}
return components;
}
// Finds self-connected sub-graphs (i.e. "components") on graph that should be read from the input stream.
// in: The input test case.
std::vector<Component> FindGraphComponents(std::istream& in) {
unsigned node_count, edge_count;
std::cin >> node_count >> edge_count;
// First build the structure that can be traversed recursively in an efficient way.
std::vector<Node> graph(node_count); // Index in this vector corresponds to node ID.
for (unsigned i = 0; i < edge_count; ++i) {
unsigned from, to;
in >> from >> to;
graph[from].Children.push_back(to);
graph[to].Parents.push_back(from);
}
return FindGraphComponents(graph);
}
void main() {
size_t test_case_count;
std::cin >> test_case_count;
for (size_t test_case_i = 1; test_case_i <= test_case_count; ++test_case_i) {
auto components = FindGraphComponents(std::cin);
// Sort components by descending size and print them.
std::sort(
components.begin(),
components.end(),
[] (const Component& a, const Component& b) { return a.size() > b.size(); }
);
std::cout << "Case " << test_case_i << ": " << components.size() << " component (s) connected (s)" << std::endl;
for (auto components_i = components.begin(); components_i != components.end(); ++components_i) {
for (auto edge_i = components_i->begin(); edge_i != components_i->end(); ++edge_i)
std::cout << *edge_i << ' ';
std::cout << std::endl;
}
std::cout << std::endl;
}
}
Call this program as...
GraphComponents.exe < input.in > output.out
...where input.in
contains data in format described in your question and it will produce the desired result in output.out
.
Upvotes: 2
Reputation: 930
You could store the components like this:
typedef vector<int> Component;
vector<Component> components;
and modify the code:
void dfs(int u){
components.back().push_back(u);
visited[ u ] = true;
for( int v = 0 ; v < adjacency[u].size(); ++v ){
if( !visited[ adjacency[u][v] ] ){
dfs( adjacency[u][v] );
}
}
}
for( int i = 0 ; i < vertex ; ++i ){ // Loop through all possible vertex
if( !visited[ i ] ){ //if we have not visited any one component from that node
components.push_back(Component());
dfs( i ); //we travel from node i the entire graph is formed
}
}
now totalComponents is components.size() :
printf("Case %d: %d component (s) connected (s)\n" ,cont++, components.size());
for (j=0;j<components.size();j++){
Component& component = components[j];
std::sort(component.begin(), component.end());
for(int k=0; k<component.size(); k++) {
printf("%d ", component[k]);
}
printf("\n");
}
components.clear();
Note that the code is not tested. Include <algorithm>
to get the sort function.
Upvotes: 0