我有以下节点和边缘集合。我想要做的是从中找到所有不同的图形。
my %connections=(36=>[31],10=>[3,4],31=>[30,22],30=>[20],22=>[20,8],20=>[1],8=>[5],5=>[2],2=>[1,20], 3=>[7]);
在这个例子中,它将产生:
my %all_graph = {
graph1 => {36=>[31],31=>[30,22],30=>[20],22=>[20,8],20=>[1],8=>[5],5=>[2],2=>[1,20]}.
graph2 => {10=>[3,4], 3=>[7]}
};
是否有任何现有算法可以做到这一点?
答案 0 :(得分:9)
使用Graph模块:
#!/usr/bin/perl
use strict; use warnings;
use Graph;
my %connections = (
36 => [ 31 ],
10 => [ 3, 4],
31 => [ 30, 22],
30 => [ 20 ],
22 => [ 20, 8],
20 => [ 1 ],
8 => [ 5 ],
5 => [ 2 ],
2 => [ 1, 20 ],
3 => [ 7 ]
);
my $g = Graph->new( undirected => 1 );
for my $src ( keys %connections ) {
for my $tgt ( @{ $connections{$src} } ) {
$g->add_edge($src, $tgt);
}
}
my @subgraphs = $g->connected_components;
my @allgraphs;
for my $subgraph ( @subgraphs ) {
push @allgraphs, {};
for my $node ( @$subgraph ) {
if ( exists $connections{ $node } ) {
$allgraphs[-1]{$node} = [ @{ $connections{$node} } ];
}
}
}
use YAML; print Dump \@allgraphs;
[sinan@archardy SO]$ ./g --- - 2: - 1 - 20 20: - 1 22: - 20 - 8 30: - 20 31: - 30 - 22 36: - 31 5: - 2 8: - 5 - 10: - 3 - 4 3: - 7
答案 1 :(得分:3)
要查找无向图的连通分量,您只需执行BFS或DFS(宽度/深度优先搜索)。
这里有一些BFS代码示例
my %connections=(36=>[31],10=>[3,4],31=>[30,22],30=>[20],22=>[20,8]
,20=>[1],8=>[5],5=>[2],2=>[1,20], 3=>[7]);
my $full_connections = {}; # Build a REAL graph with full 2-way edge lists
foreach my $node (keys %connections) {
foreach my $node2 (@{ $connections{$node} }) {
print "$node, $node2\n";
$full_connections->{$node}->{$node2} = 1;
$full_connections->{$node2}->{$node} = 1;
}
}
my %all_graph = ();
my $current_graph = 0;
my %visited = ();
my @to_visit = ();
foreach my $node (keys %$full_connections) {
next if exists $visited{$node};
# start the next segment
$current_graph++;
@to_visit=($node);
while (@to_visit) {
$node_to_visit = shift @to_visit;
#next if $visited{$node_to_visit};
$visited{$node_to_visit} = $current_graph;
push @to_visit, grep { !exists $visited{$_} }
keys %{ $full_connections->{$node_to_visit} };
}
}
# Now reconstruct %all_graph from %visited - left as exercise for the reader
print Data::Dumper->Dump([\%visited]);
答案 2 :(得分:1)
我建议使用以下算法:
1。)将所有节点移动到工作集N
。
2。)从任意节点开始执行图搜索(depth-first或breadth-first)。将所有访问过的节点和边添加到第一个子图,从N
3.如果N
非空,请选择下一个起始节点并转到步骤2.)以获取下一个子图。