Salsa Festival! All vegetables are invited! Can cycles ruin the fun?
Hi! I'm Asparagos - an asparagus who codes in Go. Here you’ll find everyday problems that a typical veggie might struggle with — and my Go solutions to them. Today we are solving the problem of Salsa Festival 🥗.
Problem
There’s a salsa festival in the Veggie Kingdom this weekend. All vegetables are invited, free of charge!
But veggies are picky: each one will only come if certain friends arrive first.
For example, bell pepper will only show up after his brother, chili pepper. A potato will only come if both pumpkin and corn are already there (this trio became best friends after the lecture "Introduction to the Carbohydrate Diet").
Nobody can untangle these complicated relationships. Did you know that apple is trying to sue pineapple for using its name?
So, can we figure out whether all the veggies will come to the salsa festival?
Input 🥒
vegNum int - the total number of vegetables in the kingdom.
requirements [][]int - each element requirements[i] = [a, b] means that vegetable a will come to the festival only if vegetable b comes first.
Output 🍅
true if it’s possible for all vegetables to attend the festival,
false if some requirements create a deadlock (i.e. a cycle).
Examples 🌶️:
-
Example 1
Input:
vegNum = 2, requirements = [[1, 0]]Output:
trueVegetable
0can come without any conditions. Vegetable1depends on0, and since0can come,1can come too. -
Example 2
Input:
vegNum = 2, requirements = [[1, 0], [0, 1]]Output:
falseVegetable
1depends on0, and0depends on1. This creates a cycle, neither can come first, so no one comes.
Solution 💡
We start by building a graph of vegetables. Each vertex represents a vegetable. An edge
a -> bmeans thatbwill only come ifacomes first. Now the problem reduces to detecting a cycle in this graph, which we can do using Depth-First Search (DFS).-
The
dfsfunction is a recursive function with the following arguments:graph [][]int- the adjacency list of the vegetable graphvertex int– the current node we are traversingpathVertices map[int]bool- tracks nodes on the current DFS path (used to detect a cycle)visited map[int]bool- tracks all previously visited nodes (used to avoid duplicate traversal)It returns
trueif a cycle is found, andfalseotherwise. -
Cycle detection logic:
If the vertex is already in
pathVertices, that means we've visited it in the current path — a cycle is found, so we returntrue.If it's already in
visitedbut not in the current path, we've checked it before and know it doesn’t lead to a cycle — returnfalse. -
Otherwise, we:
Mark the current node as visited (both in
visitedandpathVertices).Recursively apply DFS to its children.
After processing all descendants, remove the current node from
pathVertices(as we’re backtracking).If no cycles are found during any DFS traversal, return
true. Otherwise, returnfalse.
func canAllVeggiesCome(vegNum int, requirements [][]int) bool {
vegGraph := make([][]int, vegNum)
for _, req := range requirements {
toVeg := req[0]
fromVeg := req[1]
vegGraph[fromVeg] = append(vegGraph[fromVeg], toVeg)
}
visited := make(map[int]bool)
for veg := 0; veg < vegNum; veg++ {
if visited[veg] {
continue
}
pathVertices := make(map[int]bool)
if dfs(vegGraph, veg, pathVertices, visited) {
return false
}
}
return true
}
func dfs(graph [][]int, vertex int, pathVertices map[int]bool, visited map[int]bool) bool {
if pathVertices[vertex] {
return true
}
if visited[vertex] {
return false
}
pathVertices[vertex] = true
visited[vertex] = true
for _, childV := range graph[vertex] {
if dfs(graph, childV, pathVertices, visited) {
return true
}
}
pathVertices[vertex] = false
return false
}
Feel free to check out the full code with tests on GitHub, and don’t hesitate to leave a ⭐ if you find it helpful!
Top comments (0)