package LeetCode_1443
import java.util.*
import kotlin.collections.ArrayList
/**
* 1443. Minimum Time to Collect All Apples in a Tree
* https://leetcode.com/problems/minimum-time-to-collect-all-apples-in-a-tree/description/
*
* Given an undirected tree consisting of n vertices numbered from 0 to n-1, which has some apples in their vertices.
* You spend 1 second to walk over one edge of the tree.
* Return the minimum time in seconds you have to spend in order to collect all apples in the tree
* starting at vertex 0 and coming back to this vertex.
The edges of the undirected tree are given in the array edges,
where edges[i] = [fromi, toi] means that exists an edge connecting the vertices fromi and toi.
Additionally, there is a boolean array hasApple, where hasApple[i] = true means that vertex i has an apple,
otherwise, it does not have any apple.
* */
class Solution {
//bfs
fun minTime(n: Int, edges: Array<IntArray>, hasApple: List<Boolean>): Int {
var result = 0
//init and fill graph
val graph = ArrayList<ArrayList<Int>>()
val parent = Array(n, { -1 })
val dist = Array(n, { -1 })
for (i in 0 until n) {
graph.add(ArrayList())
}
for (edge in edges) {
val start = edge[0]
val end = edge[1]
graph[start].add(end)
//set the node's first visited parent
parent[end] = start
}
//measure the distance from each node from root
val queue = LinkedList<Int>()
queue.offer(0)
dist[0] = 0
while (queue.isNotEmpty()) {
val cur = queue.pop()
for (x in graph[cur]) {
if (dist[x] == -1) {
dist[x] = dist[cur] + 1
queue.offer(x)
}
}
}
/*for (i in 0 until parent.size) {
println("node $i's first visited parent is ${parent[i]}")
}*/
//accumulate the distance form each node to its first visited parent
val visited = BooleanArray(n)
for (i in n - 1 downTo 0) {
if (!visited[i] && hasApple[i]) {
//find the first visited parent of i
var q = i
while (parent[q] != -1 && !visited[q]) {
visited[q] = true
q = parent[q]
//now, q point to the first visited parent of i
}
visited[i] = true
result += (dist[i] - dist[q]) * 2
}
}
return result
}
}