package g0901_1000.s0928_minimize_malware_spread_ii

// #Hard #Array #Depth_First_Search #Breadth_First_Search #Matrix #Union_Find
// #2023_04_26_Time_716_ms_(100.00%)_Space_63.5_MB_(100.00%)

import java.util.LinkedList
import java.util.Queue

class Solution {
    private val adj: MutableMap<Int, ArrayList<Int>> = HashMap()
    private var visited: MutableSet<Int>? = null
    private var count = 0

    private fun bfs(ind: Int, initial: IntArray) {
        val q: Queue<Int> = LinkedList()
        for (i in initial.indices) {
            if (i != ind) {
                q.add(initial[i])
                visited!!.add(initial[i])
            }
        }
        while (q.isNotEmpty()) {
            val curr = q.poll()
            if (curr != initial[ind]) {
                count++
            }
            val children = adj[curr]
            if (children != null) {
                for (child in children) {
                    if (!visited!!.contains(child)) {
                        q.add(child)
                        visited!!.add(child)
                    }
                }
            }
        }
    }

    fun minMalwareSpread(graph: Array<IntArray>, initial: IntArray): Int {
        val n = graph.size
        for (i in 0 until n) {
            adj.putIfAbsent(i, ArrayList())
            for (j in 0 until n) {
                if (graph[i][j] == 1) {
                    adj.getValue(i).add(j)
                }
            }
        }
        var min = n + 1
        initial.sort()
        var node = initial[0]
        for (i in initial.indices) {
            visited = HashSet()
            val children = adj.getValue(initial[i])
            adj.remove(initial[i])
            bfs(i, initial)
            if (count < min) {
                min = count
                node = initial[i]
            }
            count = 0
            adj[initial[i]] = children
        }
        return node
    }
}
