211 lines
No EOL
6.7 KiB
Text
211 lines
No EOL
6.7 KiB
Text
---
|
||
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 metadata = {
|
||
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-list problems={metadata.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, it’s DFS, but on a grid,
|
||
and we want to find the connected component of all the connected cells with the same number.
|
||
For example, let’s 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 we’ll 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 (we’ll 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-list problems={metadata.problems.general} /> |