[英]DFS: How to indicate the nodes of the connected components in C++
我正在制作ACM競賽的問題,以確定具有無向圖G和屬於每個組件的頂點的連通組件的數量。 已經完成了DFS算法,計算了無向圖的連接組件的數量(問題的難點),但我想不出任何東西來指示屬於每個組件的節點或者有節點的記錄。
輸入:第一行輸入將是一個整數C,表示測試用例的數量。 每個測試用例的第一行包含兩個整數N和E,其中N表示圖中的節點數,E表示其中的邊數。 然后遵循E行,每行有2個整數I和J,其中I和J表示節點I和節點J之間存在邊(0≤I,J
輸出:在每個測試用例的第一行中必須顯示以下字符串“Case G:P(s)connected(s)”,其中G表示測試用例的數量(從1開始),P表示連接的組件數量在圖中。 然后是X行,每行包含屬於連接組件的節點(按從小到大的順序)用空格分隔。 每個測試用例后應打印一個空行。 輸出應寫在“output.out”中。
例:
輸入:
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
輸出:
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
這是我的代碼:
#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;
}
我懷疑如何攜帶屬於每個連接組件或結構的節點的內存應該用於存儲,我應該如何修改我的代碼來執行此操作?,我想聽聽建議,想法或偽代碼中的任何實現。 謝謝大家
該算法大致是:
結果是一組“組件”數據結構(我的實現中的std::vector
s),每個都包含一組獨占的互連節點。
注意事項:
std::vector
來有效地構建此結構。 這是工作代碼。 請注意,使用了一些C ++ 11功能,但如果使用較舊的編譯器,它們應該很容易替換。 錯誤處理留給讀者練習。
#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;
}
}
將此計划稱為......
GraphComponents.exe < input.in > output.out
...其中input.in
包含您問題中描述的格式的數據,它將在output.out
生成所需的結果。
解決方案要容易得多,你必須聲明兩個大小為頂點數的數組
int vertexNodes [vertex] / / / array to store the nodes
int vertexComponents [vertex] / / / array to store the number of components
然后,當您調用DFS時,每個頂點都存儲在頂點數組中,並存儲在該組件所屬的位置
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
}
最后,它打印總組件並創建一個標志,其中第一個組件的值與每個頂點的組件進行比較
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
}
}
您可以像這樣存儲組件:
typedef vector<int> Component;
vector<Component> components;
並修改代碼:
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
}
}
現在totalComponents是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();
請注意,代碼未經過測試。 包含<algorithm>
以獲取排序功能。
測試2個節點是否連接的通用算法:
首先,您的節點將分別位於其集合中,
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
隨着算法的進展和合並集合,它將輸入相對減半。
在上面的例子中,我想看看o1和o2之間是否有路徑。 我在合並所有邊之后才發現這條路徑。 某些圖形可能具有單獨的組件(斷開連接),這使得您無法在最后設置一個組件。 在這種情況下,您可以使用此算法測試連通性,甚至可以計算圖表中組件的數量。 組件數是算法完成時能夠獲得的集合數。
一個可能的圖形(對於上面的樹):
o-o1-o-o-o2
| |
o o
|
o
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.