Yönlendirilmiş bir grafiğin döngüsel olmadığını nasıl kontrol ederim? Ve algoritma nasıl adlandırılır? Bir referans için minnettar olurum.
Yönlendirilmiş bir grafiğin döngüsel olmadığını nasıl kontrol ederim? Ve algoritma nasıl adlandırılır? Bir referans için minnettar olurum.
Yanıtlar:
Grafiği topolojik olarak sıralamayı denerdim ve yapamazsanız, o zaman döngüleri vardır.
Basit bir derinlemesine arama yapmak, bir döngü bulmak için yeterince iyi değildir . Bir döngü mevcut olmadan bir DFS'de bir düğümü birden çok kez ziyaret etmek mümkündür. Nereden başladığınıza bağlı olarak, grafiğin tamamını da ziyaret etmeyebilirsiniz.
Bir grafiğin bağlı bir bileşenindeki döngüleri aşağıdaki gibi kontrol edebilirsiniz. Yalnızca giden kenarları olan bir düğüm bulun. Böyle bir düğüm yoksa, o zaman bir döngü vardır. Bu düğümde bir DFS başlatın. Her bir kenarı geçerken, kenarın zaten yığınızda bulunan bir düğüme işaret edip etmediğini kontrol edin. Bu bir döngünün varlığını gösterir. Böyle bir kenar bulamazsanız, o bağlı bileşende döngü yoktur.
Rutger Prins'in işaret ettiği gibi, grafiğiniz bağlı değilse, aramayı bağlı her bir bileşen üzerinde tekrarlamanız gerekir.
Referans olarak, Tarjan'ın güçlü bir şekilde bağlantılı bileşen algoritması yakından ilişkilidir. Ayrıca döngüleri bulmanıza da yardımcı olur, sadece var olup olmadıklarını bildirmez.
Kitapta Introduction to Algorithms
(İkinci Baskı) Lemma 22.11 şunu belirtir:
Yönlendirilmiş bir G grafiği, ancak ve ancak önce derinlik araması G'nin hiçbir arka kenar vermemesi durumunda çevrimsizdir
Çözüm 1:Döngüyü kontrol etmek için Kahn algoritması . Ana fikir: Derecesi sıfır olan düğümün kuyruğa ekleneceği bir kuyruk oluşturun. Ardından sıra boşalana kadar düğümü tek tek ayırın. Herhangi bir düğümün iç kenarlarının olup olmadığını kontrol edin.
Solution2 : Tarjan algoritması güçlü bağlı bileşen kontrol etmek için.
3. Çözüm : DFS . Düğümün mevcut durumunu etiketlemek için tamsayı dizisi kullanın: yani 0 - bu düğümün daha önce ziyaret edilmediği anlamına gelir. -1 - bu düğümün ziyaret edildiği ve alt düğümlerinin ziyaret edildiği anlamına gelir. 1 - bu düğümün ziyaret edildiği ve tamamlandığı anlamına gelir. Dolayısıyla, DFS yaparken bir düğümün durumu -1 ise, bu, bir döngü olması gerektiği anlamına gelir.
ShuggyCoUk tarafından verilen çözüm eksiktir çünkü tüm düğümleri kontrol etmeyebilir.
def isDAG(nodes V):
while there is an unvisited node v in V:
bool cycleFound = dfs(v)
if cyclefound:
return false
return true
Bunun zaman karmaşıklığı O (n + m) veya O (n ^ 2)
m = O(n^2)
çünkü grafiğin tamamı tam olarak m=n^2
kenarlara sahip. Yani bu O(n+m) = O(n + n^2) = O(n^2)
.
Bunun eski bir konu olduğunu biliyorum, ancak gelecekteki araştırmacılar için burada oluşturduğum bir C # uygulaması var (bunun en verimli olduğu iddiası yok!). Bu, her bir düğümü tanımlamak için basit bir tam sayı kullanmak üzere tasarlanmıştır. Düğüm nesnenizin sağlam ve eşit olması koşuluyla, istediğiniz gibi dekore edebilirsiniz.
Çok derin grafikler için, her bir düğümde derinlemesine bir hashset oluşturduğundan (bunlar enine boyuna yok edilir) yüksek ek yüke sahip olabilir.
Aramak istediğiniz düğümü girersiniz ve bu düğüme giden yol alırsınız.
Herhangi bir düğümün altındaki döngüleri kontrol ederken, o düğümü boş bir hashset ile birlikte geçirmeniz yeterlidir.
private bool FindCycle(int node, HashSet<int> path)
{
if (path.Contains(node))
return true;
var extendedPath = new HashSet<int>(path) {node};
foreach (var child in GetChildren(node))
{
if (FindCycle(child, extendedPath))
return true;
}
return false;
}
bir grafiğin döngüleri olup olmadığını bulmak için hızlı bir kod:
func isCyclic(G : Dictionary<Int,Array<Int>>,root : Int , var visited : Array<Bool>,var breadCrumb : Array<Bool>)-> Bool
{
if(breadCrumb[root] == true)
{
return true;
}
if(visited[root] == true)
{
return false;
}
visited[root] = true;
breadCrumb[root] = true;
if(G[root] != nil)
{
for child : Int in G[root]!
{
if(isCyclic(G,root : child,visited : visited,breadCrumb : breadCrumb))
{
return true;
}
}
}
breadCrumb[root] = false;
return false;
}
let G = [0:[1,2,3],1:[4,5,6],2:[3,7,6],3:[5,7,8],5:[2]];
var visited = [false,false,false,false,false,false,false,false,false];
var breadCrumb = [false,false,false,false,false,false,false,false,false];
var isthereCycles = isCyclic(G,root : 0, visited : visited, breadCrumb : breadCrumb)
Fikir şuna benzer: Ziyaret edilen düğümleri takip etmek için bir diziye sahip normal bir dfs algoritması ve mevcut düğüme götüren düğümler için bir işaretçi olarak hizmet eden ek bir dizi, böylece bir düğüm için bir dfs çalıştırdığımızda buna karşılık gelen öğeyi işaretçi dizisindeki doğru olarak ayarladık, böylece önceden ziyaret edilmiş bir düğümle karşılaşıldığında, işaretçi dizisindeki karşılık gelen öğesinin doğru olup olmadığını kontrol ederiz, eğer doğruysa, kendisine izin veren düğümlerden biridir (dolayısıyla bir döngü) ve işin püf noktası, bir düğümün df'leri geri döndüğünde, karşılık gelen işaretçisini yanlış olarak ayarlıyoruz, böylece onu başka bir rotadan tekrar ziyaret edersek kandırılmayız.
Bu soruyu bir Google röportajında aldım.
Topolojik olarak sıralamayı deneyebilirsiniz, bu O (V + E) V köşe sayısı ve E kenar sayısıdır. Yönlendirilmiş bir grafik, ancak ve ancak bu yapılabilirse döngüsel değildir.
Yaprak düğümleri, hiç kalmayana kadar özyinelemeli olarak kaldırın ve tek bir düğümden fazlası kaldıysa, bir döngünüz olur. Yanılmıyorsam, bu O (V ^ 2 + VE).
Bununla birlikte, verimli bir DFS-esque algoritması, en kötü durum O (V + E):
function isAcyclic (root) {
const previous = new Set();
function DFS (node) {
previous.add(node);
let isAcyclic = true;
for (let child of children) {
if (previous.has(node) || DFS(child)) {
isAcyclic = false;
break;
}
}
previous.delete(node);
return isAcyclic;
}
return DFS(root);
}
Yaprak düğümü soyma algoritmasının ruby uygulamam burada .
def detect_cycles(initial_graph, number_of_iterations=-1)
# If we keep peeling off leaf nodes, one of two things will happen
# A) We will eventually peel off all nodes: The graph is acyclic.
# B) We will get to a point where there is no leaf, yet the graph is not empty: The graph is cyclic.
graph = initial_graph
iteration = 0
loop do
iteration += 1
if number_of_iterations > 0 && iteration > number_of_iterations
raise "prevented infinite loop"
end
if graph.nodes.empty?
#puts "the graph is without cycles"
return false
end
leaf_nodes = graph.nodes.select { |node| node.leaving_edges.empty? }
if leaf_nodes.empty?
#puts "the graph contain cycles"
return true
end
nodes2 = graph.nodes.reject { |node| leaf_nodes.member?(node) }
edges2 = graph.edges.reject { |edge| leaf_nodes.member?(edge.destination) }
graph = Graph.new(nodes2, edges2)
end
raise "should not happen"
end
Buradaki cevabımdan bulma döngüsünü tersine çevirebilirsiniz https://stackoverflow.com/a/60196714/1763149
def is_acyclic(graph):
return not has_cycle(graph)