![](/img/trans.png)
[英]Given a weighted graph and natural number k how to find the cheapest path from node s to t that can be divided by k?
[英]given a number k and a graph is there a DFS run that will give forest larger then k
在對問題進行編輯后:
使用Kosaraju 算法在 O(V + E) 時間內得到強連通分量。 這將給出最大 K。
這里 max K 與強連通分量的數量相同。
為什么?
現在讓我們用反證法來證明。 假設問題中顯示的圖表有 4 個強連通分量。 假設有可能從某個節點v
開始獲得額外的 dfs 樹。 這意味着要么在計算強連接組件的數量時未覆蓋節點v
,要么在 DFS 期間錯過了節點。 但是,如果我們進行 DFS 或使用經過充分驗證的算法找到強連通分量,則任何一種情況都是不可能的。 因此,我們的假設是錯誤的。 於是,反證法。
在編輯問題之前回答:
DFS(Vertex v):
mark v as visited;
for(Vertex neighbor: Neighbors of v){
if(!isVisited(neighbor)){
DFS(neighbor);
})
}
count_trees(Graph G): //V vertices and E edges in total
for(Vertex v: V){
if(!isVisited(v)){
DFS(v);
trees++;
})
}
return trees;
以上步驟是不言自明的。 維護一個頂點是否被訪問是微不足道的。
上面的方法只是在之前沒有訪問過的每個節點上進行 DFS。 因此,時間復雜度與 DFS 相同,為O(|V| + |E|)
。
想象給定的圖實際上是一棵樹。 然后,如果您在樹的根部啟動一個 DFS,您將在一次 DFS 搜索中找到整個圖。 在另一個極端,如果你在一個葉子中啟動一個 DFS,然后在下一個葉子中,並在節點中啟動每個新的 DFS,就像你讓它們自下而上一樣,那么每個 DFS 將只找到一個節點,然后退出(因為之前的 DFS 已經訪問過孩子)。 因此,您可以啟動與樹中的節點一樣多的 DFS 搜索。
如果圖有一些額外的邊,同樣如此,但仍然是非循環的。
當圖形有循環時,它會變得不同。 在這種情況下,從循環的任何成員開始的 DFS 將找到該循環中的所有其他成員。 因此,一個循環永遠不會被不同的 DFS 搜索分割。 這個循環,加上與之相交的所有其他循環,就是所謂的強連通分量。
因此,算法必須找到強連接的組件並將其計為 1 個 DFS,而所有其他不參與任何循環的節點都可以計為一個單獨的 DFS(因為您將從這些子樹的葉子開始)。
這是一個使用 DFS 的算法(這很令人困惑,因為它是一個 DFS 計算可能的 DFS)來識別周期並相應地更新計數。 我已經為這個算法使用了遞歸,因此當達到所需的k時必須有一些快速回溯:在這種情況下不需要進一步搜索。
所有邊只訪問一次,主循環也只訪問所有節點一次,因此達到了所需的時間復雜度。
def k_forests(adj, k):
# pathindex[node] == 0: means node has not been visited
# pathindex[node] == -1: means node has been visited and all neighbors processed
# pathindex[node] > 0: means node is at this step in the current DFS path
pathindex = [0] * len(adj) # none of the nodes has been visited
def recur(node, depth):
nonlocal k # we will decrease this count
if pathindex[node] > 0: # cycle back
return pathindex[node]
if pathindex[node] == -1: # already processed
return depth
pathindex[node] = depth # being visited
cycle = depth + 1 # infinity
for neighbor in adj[node]:
cycle = min(cycle, recur(neighbor, depth + 1))
if k == 0: # success
return -1 # backtrack completely...
if cycle >= depth: # no cylce detected or back out of cycle
k -= 1
if k == 0:
return -1 # success
pathindex[node] = -1 # completely visited and processed
return cycle
# main loop over the nodes
for node in range(len(adj)):
recur(node, 1)
if k == 0:
return "YES"
return "NO"
調用這個function應該每個節點都有一個鄰接表,其中節點是用一個序號標識的,從0開始。例如問題中的圖可以表示如下,其中s=0,t=1,u =2,v=3,w=4,x=5,y=6,z=7:
adj = [
[4, 7],
[2, 3],
[3, 1],
[0, 4],
[5],
[7],
[5],
[6, 4]
]
print(k_forests(adj, 4)) # YES
print(k_forests(adj, 5)) # NO
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.