Algoritmo de teoría de grafos (6): ejercicio de algoritmo de teoría de grafos de LeetCode (785. Gráfico bipartito de evaluación, 695. Área máxima de la isla, algoritmo de inundación, búsqueda de unión)

El contenido de este capítulo está implementado en Java, almacén de código de Github: https://github.com/ZhekaiLi/Code/tree/main/Graph/src

¡Ver las imágenes en el artículo puede requerir acceso científico a Internet!Debido a que github se usa para administrar imágenes, si hay una situación que no se puede cargar, voltee la pared

[Referencia] imooc Mr. Bobo: Fun Algorithm Series - Graph Theory Essentials for Interview and Promotion (Java Edition)

[Enlaces a blogs anteriores]
Algoritmos de teoría de grafos (1, 2): clasificación de grafos, conceptos básicos de grafos (gráficos no dirigidos y gráficos dirigidos, gráficos no ponderados, gráficos acíclicos, gráficos completos, gráficos bipartitos; gráficos simples, componentes de gráficos conectados, expansión árbol de gráficos, subgráficos y gráficos principales)
algoritmo de teoría de gráficos (3): representación básica de gráficos (matriz de adyacencia, lista de adyacencia, comparación de matriz de adyacencia y lista de adyacencia)
algoritmo de teoría de gráficos (4): primera profundidad de gráficos
Teoría de gráficos DFS transversal Algoritmo (5): Amplitud de gráfico Primer recorrido BFS
Algoritmo de teoría de gráficos (6): LeetCode Ejercicio de algoritmo de teoría de gráficos (785. Juicio de gráfico bipartito, 695. Área máxima de isla, Algoritmo de relleno de inundación, Verificación de unión)

6 ejercicios de algoritmo de teoría de grafos de LeetCode

785. Evaluación de gráficos bipartitos

Puede consultar la Sección 4.4

Implementación de java: LeetCode785_me.java (el autor usó BFS)

695. Superficie máxima de islas

El núcleo de este problema es el modelado de gráficos, que consiste en extraer información de puntos y bordes de la matriz bidimensional dada por el título. Nuestro objetivo es poner la siguiente matriz

[[0,0,1,0,0,0,0,1,0,0,0,0,0],
 [0,0,0,0,0,0,0,1,1,1,0,0,0],
 [0,1,1,0,1,0,0,0,0,0,0,0,0],
 [0,1,0,0,1,1,0,0,1,0,1,0,0],
 [0,1,0,0,1,1,0,0,1,1,1,0,0],
 [0,0,0,0,0,0,0,0,0,0,1,0,0],
 [0,0,0,0,0,0,0,1,1,1,0,0,0],
 [0,0,0,0,0,0,0,1,1,0,0,0,0]]

Convertido a

// AdjList[i] 储存结点i的邻接点
AdjList = [[1, 4, 8], [2, 7, 9], ...]

Sin embargo, los nodos en la lista de adyacencia tradicional se representan como números enteros, mientras que en la matriz madre, los nodos están representados por parámetros de posición bidimensionales.Los pasos principales son los siguientes:
(1) Mapear la información del nodo de bidimensional a unidimensional



(2) Determinar si algún nodo tiene puntos adyacentes



(3) De acuerdo con el algoritmo escrito anteriormente para resolver los componentes conectados de grafos no dirigidos, complete el cuerpo principal del código

Puede consultar la Sección 4.1

implementación de java v1: LeetCode695_me.java(LeetCode muestra que superé al 5,3% de los usuarios..., qué mierda. Puede ser que se utilicen algunas estructuras de datos relativamente complejas, pero en términos de lógica, personalmente creo que está bastante bien)
implementación de java v2: LeetCode695.java(Mejor ejemplo de código)
Primero convierta la matriz 2D para HashSetescribir información gráfica, luego use dfs. Código central:

private int[][] dirs = {
    
    {
    
    -1, 0}, {
    
    0, 1}, {
    
    1, 0}, {
    
    0, -1}}; // 四连通

private HashSet<Integer>[] constructGraph(){
    
    
    HashSet<Integer>[] g = new HashSet[R * C];
    for (int i = 0; i < g.length; i++)
        g[i] = new HashSet<>();

    for (int v = 0; v < g.length; v++) {
    
    
        int x = v / C, y = v % C; // 将一维信息转化为二维坐标
        if (grid[x][y] == 1) {
    
    
            for (int d = 0; d < 4; d++) {
    
    
                int nextx = x + dirs[d][0], nexty = y + dirs[d][1];
                if (inArea(nextx, nexty) && grid[nextx][nexty] == 1){
    
    
                    int next = nextx * C + nexty;
                    g[v].add(next);
                }}}}
    return g;
}

private int dfs(int v){
    
    
    visited[v] = true;
    int res = 1;
    for(int w: G[v]){
    
    
        if(!visited[w])
            res += dfs(w);
    }
    return res;
}

implementación java v3: LeetCode695_plus.java
Utilice directamente la matriz bidimensional de entrada para guardar la información del gráfico y transforme el dfs para que sea adecuado para la entrada bidimensional. Código central:

private int dfs(int x, int y){
    
    
    visited[x][y] = true;
    int res = 1;
    for(int d = 0; d < 4; d++){
    
    
        int nextx = x + dirs[d][0], nexty = y + dirs[d][1];
        if(inArea(nextx, nexty) && !visited[nextx][nexty] && grid[nextx][nexty] == 1)
            res += dfs(nextx, nexty);
    }
    return res;
}

6.1 algoritmo de inundación

El último fragmento de código de la sección anterior (implementación de Java v3) también se denomina algoritmo de inundación, que es esencialmente el mismo que dfs, excepto que el método original de propagación basado en bordes se cambia a propagación en cuatro direcciones en el sistema de coordenadas. . . El ejemplo es el siguiente:



Aplicación de relleno de inundación

Juego de varita mágica y buscaminas en ps.



Preguntas relacionadas en LeetCode

200. Número de islas
1020. Número de enclaves
130. Área rodeada
733. Representación de imágenes (relleno de inundación)
1034. Color de borde
529. Juego de buscaminas
827. Isla artificial más grande [Difícil]

6.2 Conectividad y Uniones

class UF{
    
    
    private int[] parent;

    public UF(int n){
    
    
        parent = new int[n];
        for(int i = 0 ; i < n ; i ++)
            parent[i] = i;
    }

    public int find(int p){
    
    
        if( p != parent[p] )
            parent[p] = find( parent[p] );
        return parent[p];
    }

    public boolean isConnected(int p , int q){
    
    
        return find(p) == find(q);
    }

    public void unionElements(int p, int q){
    
    
        int pRoot = find(p);
        int qRoot = find(q);
        if( pRoot == qRoot )
            return;
        parent[pRoot] = qRoot;
    }
}

A continuación, se mostrará el proceso de creación y ejecución del conjunto de consultas de unión en una combinación de diagrama y código:

UF uf = new UF(6);


uf.unionElements(2, 1);
uf.unionElements(3, 1);
uf.unionElements(5, 4);
uf.unionElements(6, 4);


uf.unionElements(4, 1);


Cabe señalar que find(int p)la función no solo puede devolver el nodo raíz del nodo p, sino también cambiar directamente el nodo principal del nodo p a su nodo raíz cada vez que se ejecuta. Una implementación tan funcional puede evitar una larga lista de conexiones

Además, podemos mejorar la UFclase para ayudar a encontrar la cantidad de elementos en la colección de cualquier elemento.

class UF{
    
    
    private int[] parent;
    private int[] sz; // 1. 我们需要一个 sz 数组,存储以第 i 个元素为根节点的集合的元素个数。

    public UF(int n){
    
    
        parent = new int[n];
        sz = new int[n];
        for(int i = 0 ; i < n ; i ++){
    
    
            parent[i] = i;
            sz[i] = 1; // 2. 初始化,每个 sz[i] = 1
        }
    }

    public int find(int p){
    
     // 没有变化... }
    public boolean isConnected(int p , int q){
    
     // 没有变化 }

    public void unionElements(int p, int q){
    
    
        int pRoot = find(p);
        int qRoot = find(q);
        if( pRoot == qRoot )
            return;
        parent[pRoot] = qRoot;
        // 3. 维护 sz:把 qRoot 的集合元素数量加上 pRoot 的集合元素数量
        sz[qRoot] += sz[pRoot];
    }

    // 4. 最后,设计一个接口让用户可以查询到任意一个元素 p 所在的集合的元素个数 
    public int size(int p){
    
    
        return sz[find(p)]; // 使用 p 所在的集合的根节点查找相应的元素个数
    }
}

Ejercicio de LeetCode usando floodfill + union

695. Superficie máxima de islas

Supongo que te gusta

Origin blog.csdn.net/weixin_43728138/article/details/118993955
Recomendado
Clasificación