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/Flood_Fill.mdx

209 lines
6.7 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: ff
title: Flood Fill
author: Darren Yao
prerequisites:
- dfs
description: "A variant of DFS which finds connected components in a graph respresented by a grid."
frequency: 3
---
import { Problem } from "../models";
export const problems = {
sample: [
new Problem("LC", "Flood Fill", "https://leetcode.com/problems/flood-fill/", "Intro|Easy", false, []),
new Problem("CSES", "Counting Rooms", "1192", "Easy", false, []),
],
general: [
new Problem("CSES", "Labyrinth", "1193", "Easy", false, []),
new Problem("Silver", "Count Cross", "716", "Easy", false, ["FF"]),
new Problem("Silver", "Ice Perimeter", "895", "Easy", false, []),
new Problem("Silver", "Switching on the Lights", "570", "Normal", false, []),
new Problem("Silver", "Build Gates", "596", "Normal", false, []),
new Problem("Silver", "Milk Pails", "620", "Normal", false, []),
new Problem("Silver", "Where's Bessie?", "740", "Normal", false, []),
new Problem("Silver", "Why Did the Cow Cross the Road III", "716", "Normal", false, []),
new Problem("Silver", "Multiplayer Moo", "836", "Hard", false, []),
new Problem("Silver", "Snow Boots", "811", "Hard", false, []),
new Problem("Silver", "Mooyo Mooyo", "860", "Hard", false, []),
],
};
<Problems problems={problems.sample} />
<br />
<Resources>
<Resource source="IUSACO" title="10.5 - Flood Fill">module is based off this</Resource>
</Resources>
**Flood fill** is an algorithm that identifies and labels the connected component that a
particular cell belongs to, in a multi-dimensional array. Essentially, its DFS, but on a grid,
and we want to find the connected component of all the connected cells with the same number.
For example, lets look at the following grid and see how floodfill works, starting from the
top-left cell. The color scheme will be the same: red for the node currently being processed,
blue for nodes already visited, and uncolored for nodes not yet visited.
(tables)
<IncompleteSection />
As opposed to an explicit graph where the edges are given, a grid is an implicit graph.
This means that the neighbors are just the nodes directly adjacent in the four cardinal
directions.
Usually, grids given in problems will be $N$ by $M$, so the first line of the input contains the
numbers $N$ and $M$. In this example, we will use an two-dimensional integer array to store the
grid, but depending on the problem, a two-dimensional character array or a two-dimensional
boolean array may be more appropriate. Then, there are $N$ rows, each with $M$ numbers
containing the contents of each square in the grid. Example input might look like the following
(varies between problems):
```
3 4
1 1 2 1
2 3 2 1
1 3 3 3
```
And well want to input the grid as follows:
```java
static int[][] grid;
static int n, m;
public static void main(String[] args){
int n = r.nextInt();
int m = r.nextInt();
grid = new int[n][m];
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
grid[i][j] = r.nextInt();
}
}
}
```
```cpp
int grid[MAXN][MAXM];
int n, m;
int main(){
cin >> n >> m;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
cin >> grid[i][j];
}
}
return 0;
}
```
## Implementation
<Resources>
<Resource source="GFG" title="Flood Fill" url="flood-fill-algorithm-implement-fill-paint"></Resource>
</Resources>
When doing floodfill, we will maintain an $N\times M$ array of booleans to keep track of
which squares have been visited, and a global variable to maintain the size of the current
component we are visiting. Make sure to store the grid, the visited array, dimensions, and
the current size variable globally.
This means that we want to recursively call the search function from the squares above,
below, and to the left and right of our current square. The algorithm to find the size of a
connected component in a grid using floodfill is as follows (well also maintain a 2D visited array).
<LanguageSection>
<CPPSection>
```cpp
int grid[MAXN][MAXM]; // the grid itself
int n, m; // grid dimensions, rows and columns
bool visited[MAXN][MAXM]; // keeps track of which nodes have been visited
int currentSize = 0; // reset to 0 each time we start a new component
void floodfill(int r, int c, int color){
if(r < 0 || r >= n || c < 0 || c >= m) return; // if outside grid
if(grid[r][c] != color) return; // wrong color
if(visited[r][c]) return; // already visited this square
visited[r][c] = true; // mark current square as visited
currentSize++; // increment the size for each square we visit
// recursively call floodfill for neighboring squares
floodfill(r, c+1, color);
floodfill(r, c-1, color);
floodfill(r-1, c, color);
floodfill(r+1, c, color);
}
int main(){
/**
* input code and other problem-specific stuff here
*/
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(!visited[i][j]){
currentSize = 0;
floodfill(i, j, grid[i][j]);
// start a floodfill if the square hasn't
// already been visited, and then
// store or otherwise use the component size for whatever
// it's needed for
}
}
}
return 0;
}
```
</CPPSection>
<JavaSection>
```java
static int[][] grid; // the grid itself
static int n, m; // grid dimensions, rows and columns
static boolean[][] visited; // keeps track of which nodes have been visited
static int currentSize = 0; // reset to 0 each time we start a new component
public static void main(String[] args){
/**
* input code and other problem-specific stuff here
*/
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(!visited[i][j]){
currentSize = 0;
floodfill(i, j, grid[i][j]);
// start a floodfill if the square hasn't already been visited,
// and then store or otherwise use the component size
// for whatever it's needed for
}
}
}
}
static void floodfill(int r, int c, int color){
if(r < 0 || r >= n || c < 0 || c >= m) return; // if outside grid
if(grid[r][c] != color) return; // wrong color
if(visited[r][c]) return; // already visited this square
visited[r][c] = true; // mark current square as visited
currentSize++; // increment the size for each square we visit
// recursively call floodfill for neighboring squares
floodfill(r, c+1, color);
floodfill(r, c-1, color);
floodfill(r-1, c, color);
floodfill(r+1, c, color);
}
```
</JavaSection>
</LanguageSection>
## Problems
<Problems problems={problems.general} />