Menemukan ketinggian semua node di hutan

8

Saya memiliki hutan, yaitu node dengan tepi terarah dan tanpa siklus (terarah atau tidak terarah). Saya mendefinisikan ketinggian suatu simpulv sebagai 0 jika tidak memiliki tepi masuk, atau jumlah tepi maksimum untuk dilalui secara terbalik untuk mencapai puncak ketinggian 0. masukkan deskripsi gambar di sini

Saya juga tahu bahwa derajat rata-rata sebuah simpul adalah konstanta kecil, katakanlah 2 atau lebih. Untuk menemukan ketinggian semua simpul, saya dapat memikirkan dua algoritma:

Algoritma Berjalan

  1. Pergi melalui dan tandai untuk simpul tanpa tepi masuk.h=0
  2. Untuk setiap simpul dengan , ikuti tepi keluar, perbarui ketinggian setiap simpul yang ditemui jika ketinggian sebelumnya lebih kecil.h=0

Algoritma Perbatasan

  1. Pergi melalui dan tandai untuk simpul tanpa tepi masuk, dan tandai ini sebagai perbatasan.h=0
  2. Untuk setiap titik perbatasan, lihat apakah orang tuanya memiliki anak di atau di bawah batas, Jika ya, tandai orang tua memiliki ditambah tinggi terbesar di antara anak-anaknya. Tandai orang tua sebagai berada di perbatasan.1
  3. Ulangi 2 sampai tidak ada apa-apa di luar perbatasan.

Pertanyaan saya:

  1. Apakah ada nama untuk masalah ini, dan solusi tercepat yang terkenal?
  2. Saya cenderung berpikir hanya berjalan dari semua simpul adalah solusi tercepat. Apakah saya benar?h=0
highBandWidth
sumber

Jawaban:

7

Pertama-tama, sedikit tergantung bagaimana Anda dapat mengakses data Anda untuk mengatakan algoritma mana yang bekerja paling baik.

Bagaimanapun, saya akan menyarankan untuk menentukan ketinggian secara top-down daripada bottom-up. Saya pribadi berpikir bahwa pendekatan top-down secara konseptual lebih baik dan lebih mudah untuk dianalisis. Untuk setiap titikv di hutan memang benar itu

height(v)={(maxu child of vheight(u))+1if u is not a leaf0otherwise.

So you can scan for all roots, and then determine the heights by divide an conquer. You will touch every vertex at most twice (scanning for the roots + traversing). In the approach that you have suggested you might have to touch some vertices many times.

Btw, since you have a forest, you have less edges than vertices, so you know that you have average degree less than two (and therefore you can test for roots in linear time).

A.Schulz
sumber
+1; recursive solutions are often easier to analyze. It also depends on whether you already have child pointers or not, and whether you want a loop-based or recursion-based solution.
Joe
Saya suka analisisnya! Adakah yang bisa membantu para pemula menunjukkan cara mengonversikan ini ke bentuk berulang juga?
highBandWidth
4

I don't know if this problem has an official name or not. Your title sums it up well enough. Walking up from the 0 height nodes will be fast, provided you take care to avoid duplicate work. Suppose you have a node with many children and a long path above this node to the root. Suppose also that the heights of each of the children are different. Each child may update the height of the node in question. That's ok. But you should avoid also updating the long path above that node until all its children have reported their heights.

The resulting algorithm will run in linear time, and the pseudo-code would look something like this:

initialize a queue Q
initialize all nodes to have a property: maxChildHeight = 0
initialize all nodes of in-degree 0 to have height = 0
Add all nodes of in-degree 0 to Q
while Q is non-empty:
  pop a node v from the front of Q
  subtract 1 from the indegree of the parent of v
  set parent.maxChildHeight = max(height(v), parent.maxChildHeight)
  if the indegree of the parent is 0:
      parent.height =  maxChildHeight + 1
      add the parent to Q
Joe
sumber
3

A problem so similar it might be of interest is "Parallel Prefix on Rooted Directed Trees." The algorithm finds the number of edges to the root from each node. So the roots ends up with a the value 0, while e.g. the bottom right node would end up with a value of two.

Note that the algorithm below solves the more general problem for weighted edges, but you can just initialize the W(i) to 1 for all i. And each node i's successor is given by P(i)=j.

for 1 ≤ i ≤ n do in parallel
    S(i) = P(i)
    while S(i) != S(S(i)) do
        W(i) = W(i) + W(S(i))
        S(i) = S(S(i))

The image below illustrates the "halving" of the path lengths and makes the logarithmic running time easy to understand. It does not show the node heights computed though.

enter image description here

(from "Introduction to Parallel Algorithms" by Joseph Jaja).

Using multiple processors, it is solvable in O(lg n) time, but uses O(n lg n) operations. There is a hack to get it down to linear work, but it is slightly involved.

The Unfun Cat
sumber
Thanks! what does S(i) represent?
highBandWidth
The successor node. So in iteration one of the right tree, S(9) = 10, S(10)=11, S(11)=12, S(12)=13 and W(9) = 1, W(10)=1, W(11)=1, W(12)=1. In iteration two, S(9) = 11, S(10)=12, S(11)=13, S(12)=13 and W(9) = 2, W(10)=2, W(11)=2, W(12)=1. In iteration three, S(9) = 13, S(10)=13, S(11)=13, S(12)=13 and W(9) = 2 + 2, W(10)=2+1, W(11)=2, W(12)=1.
The Unfun Cat
You must imagine all the S(i) and W(i) are updated at the same time when you try to work out the details. This might be obscure, but I wanted to post it because it is a classic parallel problem and very close to what you described.
The Unfun Cat