This repository has been archived on 2022-06-22. You can view files and clone it, but cannot push or open issues or pull requests.
usaco-guide/content/3_Silver/DFS.mdx
2020-07-18 21:36:48 -04:00

272 lines
7.4 KiB
Text

---
id: dfs
title: Depth First Search (DFS)
author: Siyong Huang
prerequisites:
- intro-graphs
description: "A way to recursively traverse through a graph."
frequency: 4
---
import { Problem } from "../models";
export const metadata = {
problems: {
sample: [
new Problem("CSES", "Building Roads", "1666", "Intro|Easy", false, ["DFS"]),
],
general: [
new Problem("CF", "Bear & Friendship", "problemset/problem/771/A", "Easy", false, ["DFS"]),
new Problem("Silver", "Closing the Farm", "644", "Easy", false, ["DFS"]),
new Problem("Silver", "Moocast", "668", "Easy", false, ["DFS"]),
new Problem("Silver", "Fence Planning", "944", "Easy", false, ["DFS"]),
new Problem("Kattis", "Birthday Party", "birthday", "Easy", false, ["DFS"], "DFS with each edge removed"),
new Problem("Silver", "Mootube", "788", "Easy", false, ["Tree", "DFS"]),
new Problem("CF", "PolandBall & Forest", "problemset/problem/755/C", "Easy", false, ["Tree", "DFS"]),
new Problem("Silver", "Milk Visits", "968", "Normal", false, ["DFS"]),
new Problem("Silver", "Milk Pails", "620", "Normal", false, ["DFS"]),
new Problem("Silver", "Wormhole Sort", "992", "Normal", false, ["DFS", "Binary Search"]),
new Problem("Silver", "Moo Particle", "1040", "Normal", false, ["Sorting"]),
new Problem("Gold", "Moocast", "669", "Normal", false, [], ""),
],
tree: [
new Problem("CSES", "Subordinates", "1674", "Very Easy", false, ["Tree", "DFS"]),
new Problem("CF", "Journey", "contest/839/problem/C", "Easy", false, ["Tree", "DFS"]),
new Problem("CSES", "Tree Diameter", "1131", "Normal", false, ["Tree", "DFS"]),
new Problem("CSES", "Tree Distances I", "1132", "Normal", false, ["Tree", "DFS"]),
new Problem("CSES", "Tree Distances II", "1133", "Normal", false, ["Tree", "DFS"]),
new Problem("CF", "Wizard's Tour", "contest/860/problem/D", "Normal", false, ["Tree", "DFS"]),
new Problem("POI", "Hotels", "https://szkopul.edu.pl/problemset/problem/gDw3iFkeVm7ZA3j_16-XR7jI/site/?key=statement", "Normal", false, ["Tree", "DFS"]),
new Problem("HE", "Birthday Gifts", "https://www.hackerearth.com/practice/math/combinatorics/inclusion-exclusion/practice-problems/algorithm/mancunian-and-birthday-gifts-d44faa15/description/", "Normal", false, ["Tree", "PIE"], ""),
new Problem("CSA", "Tree Construction", "contest/860/problem/D", "Hard", false, ["Tree", "DFS"], "several cases"),
new Problem("Gold", "Cow At Large", "790", "Hard", false, [], ""),
],
bipsample: [
new Problem("CSES", "Building Teams", "1668", "Easy", false, ["Bipartite"]),
],
bip: [
new Problem("CF", "Bipartiteness", "contest/862/problem/B", "Easy", false, ["Bipartite"]),
new Problem("Silver", "The Great Revegetation", "920", "Easy", false, ["Bipartite"]),
new Problem("Silver", "Clock Tree", "1016", "Hard", false, []),
],
}
};
## Resources
<Resources>
<Resource source="CPH" title="12.1 - DFS, 14 - Tree algorithms" starred></Resource>
<Resource source="CSA" title="Depth First Search" url="depth_first_search" starred>interactive</Resource>
<Resource source="IUSACO" title="10.4 - Graph Traversal Algorithms"></Resource>
<Resource source="PAPS" title="12.2 - Depth-First Search">with an example problem</Resource>
<Resource source="CPC" title="7 - Graphs 1" url="07_graphs_1">fast-paced</Resource>
<Resource source="cp-algo" title="Depth First Search" url="graph/depth-first-search.html">hard to parse for a beginner</Resource>
<Resource source="TC" title="Graphs Section 2" url="introduction-to-graphs-and-their-data-structures-section-2"></Resource>
</Resources>
## Counting Connected Components
<Problems problems={metadata.problems.sample} />
### Implementation
Iterate through each node. If it has not been visited, visit it and all other nodes in its component. The number of times we perform the visiting operation is the number of connected components.
<LanguageSection>
<CPPSection>
```cpp
//UNTESTED
bool visited[MN];
void dfs(int node)
{
visited[node] = true;
for(int u:adj_list[node])
if(!visited[u])
dfs(u);
}
int count_components()
{
int count=0;
for(int i=1;i<=N;++i)
if(!visited[i])
dfs(i), ++count;
return count;
}
```
</CPPSection>
<JavaSection>
```java
//UNTESTED
boolean[] visited = new boolean[MN];
public static void dfs(int node)
{
visited[node] = true;
for(int u:adj_list[node])
if(!visited[u])
dfs(u);
}
public static int count_components()
{
int count=0;
for(int i=1;i<=N;++i)
if(!visited[i])
dfs(i), ++count;
return count;
}
```
</JavaSection>
</LanguageSection>
<IncompleteSection />
### Problems
<Problems problems={metadata.problems.general} />
## Tree Problems
### Implementation
Trees are generally treated very differently from general graph problems.
Typically, after arbitrarily rooting a tree, some interesting pieces of information are a node's parent, subtree size, and depth.
The implementation below computes those numbers.
<LanguageSection>
<CPPSection>
```cpp
//untested
int parent[MN];
int subtree_size[MN];
int depth[MN];
void dfs(int node)
{
subtree_size[node] = 1;
for(auto u:adj_list[node])
if(u != parent[node])
{
parent[u] = node;
depth[u] = depth[node] + 1;
dfs(u);
subtree_size[node] += subtree_size[u];
}
}
```
</CPPSection>
<JavaSection>
```java
//untested
int[] parent = new int[MN];
int[] subtree_size = new int[MN];
int[] depth = new int[MN];
public static void dfs(int node)
{
subtree_size[node] = 1;
for(auto u:adj_list[node])
if(u != parent[node])
{
parent[u] = node;
depth[u] = depth[node] + 1;
dfs(u);
subtree_size[node] += subtree_size[u];
}
}
```
</JavaSection>
</LanguageSection>
<IncompleteSection />
### Problems
<Problems problems={metadata.problems.tree} />
## Graph Two-Coloring
*Graph two-coloring* refers to assigning a boolean value to each node of the graph, dictated by the edge configuration.
The most common example of a two-colored graph is a *bipartite graph*, in which each edge connects two nodes of opposite colors.
<Problems problems={metadata.problems.bipsample} />
### Resources
<Resources>
<Resource source="IUSACO" title="10.7 - Bipartite Graphs" starred></Resource>
<Resource source="CPH" title="12.3 - Graph Traversal: Applications"></Resource>
<Resource source="cp-algo" title="Bipartite Check" url="graph/bipartite-check.html">Uses BFS, but DFS accomplishes the same task.</Resource>
</Resources>
### Implementation
The idea is that we can arbitrarily label a node and then run DFS. Every time we visit a new (unvisited) node, we set its color based on the edge rule. When we visit a previously visited node, check to see whether its color matches the edge rule. For example, an implementation of coloring a bipartite graph is shown below.
<LanguageSection>
<CPPSection>
```cpp
//UNTESTED
bool is_bipartite = true;
void dfs(int node)
{
visited[node] = true;
for(int u:adj_list[node])
if(visited[u])
{
if(color[u] == color[node])
is_bipartite = false;
}
else
{
color[u] = !color[node];
dfs(u);
}
}
```
</CPPSection>
<JavaSection>
```java
//UNTESTED
boolean is_bipartite = true;
public static void dfs(int node)
{
visited[node] = true;
for(int u:adj_list[node])
if(visited[u])
{
if(color[u] == color[node])
is_bipartite = false;
}
else
{
color[u] = !color[node];
dfs(u);
}
}
```
</JavaSection>
</LanguageSection>
### Problems
<Problems problems={metadata.problems.bip} />