• 算法很美 笔记 12.图结构


    12.图结构

    1. 图基础

    定义和基本术语

    • 图(graph)是一种网状数据结构,图是由非空的顶点集合和一个描述顶点之间关系的集合组成。

    • 图由顶点和边组成,顶点表示对象,,边表示两个对象间的连接关系。

    • 图大体分两种,边没有指向性的叫无向图,边具有指向性的叫有向图

    • 边可以带权值,称为带权图

    无向图术语

    • 两个顶点之间如果有边连接,视为两个顶点相邻

    • 相邻顶点的序列称为路径

    • 起点和终点重合的路径称为,特殊路径

    • 任意两点之间都存在路径连接的图称为连通图

    • 顶点连接的边数叫做这个顶点的

    树与图

    • 没有圈连通图,就是树

    • 没有圈的非连通图,就是森林

    • 一棵树的边数等于顶点数-1

    • 边数等于顶点数-1的连通图,就是树

    有向图的术语

    • 没有圈的有向图,叫做DAG (Directed Acyclic Graph,有向无环图)

    • 拓扑排序定义:将DAG中的顶点以线性方式进行排序。即对于任何自顶点u到顶点v的有向边u->v ,在最后的排序结果中,顶点u总是在顶点v的前面。这样的排序结果,称为拓扑序。

    2. 图的表示

    邻接矩阵(adjacency matrix )

    • 无向图的邻接矩阵是对称矩阵,有向时不一定;

    • 不带权时用1/0表示是否有边;带权时,数值就是权值

    邻接表(adjacency list)

    • 邻接表更加节约空间

    • 但是,查询两点是否有边需遍历链表

    • 而且,保存权值需要另外存储一个边集

    3. dfs及相关问题

    题1:四连通检测

    给定一个方阵,定义连通:上下左右相邻,并且值相同。可以想象成一张地图,不同的区域被涂以不同颜色。
    输入:整数N, (N<50)表示矩阵的行列数,接下来N行,每行N个字符,代表方阵中的元素,接下来一个整数M,(M<1000)表示询问数接下来M行,每行代表一个询问,格式为4个整数,y1,x1,y2,x2,表示询问(第y1行,第x1列) 与 (第y2行,第x2列) 是否连通。连通输出true,否则false

    输入:
    10
    0010000000
    0011100000
    0000111110
    0001100010
    1111010010
    0000010010
    0000010011
    0111111000
    0000010000
    0000000000
    3
    0 0 9 9
    0 2 6 8
    4 4 4 6
    输出:
    false
    true
    true
    
    public class 图的dfs_连通检测 {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int N = scanner.nextInt();
            scanner.nextLine();
            char[][] graph = new char[N][N];
            for (int i = 0; i < N; i++) {
                graph[i] = scanner.nextLine().toCharArray();
            }
            int M = scanner.nextInt();
            int[][] query = new int[M][4];
            for (int i = 0; i < M; i++) {
                for (int j = 0; j < 4; j++) {
                    query[i][j] = scanner.nextInt();
                }
            }
            // M个起点和终点
            for (int i = 0; i < M; i++) {
                //对每个起点和终点,检查是否连通
                boolean ok = check(graph, new int[N][N], query[i]);
                System.out.println(ok);
            }
        }
    
        /**
         * 检查两个坐标点在这个图中是否连通
         * @param graph 原始图
         * @param label 标记
         * @param points 起点和终点的坐标 x1 y1 x2 y2
         * @return
         */
        private static boolean check(char[][] graph, int[][] label, int[] points) {
            int x1 = points[0];
            int y1 = points[1];
            int x2 = points[2];
            int y2 = points[3];
            //起点和终点重合了,就可以返回true
            if (x1 == x2 && y1 == y2) {
                return true;
            }
    
            int value = graph[x1][y1];
            boolean f1 = false;
            boolean f2 = false;
            boolean f3 = false;
            boolean f4 = false;
            //往左走,1.不能走出去,2.左边的位置没有被访问过,3.左边位置上的值要和现在的值相同
            if (x1 - 1 >= 0 && label[x1 - 1][y1] == 0 && graph[x1 - 1][y1] == value) {
                label[x1 - 1][y1] = 1; // 坐标的位置标记为已访问
                points[0] = x1 - 1; // 把左边的点作为新起点,递归
                f1 = check(graph, label, points);
                //回溯
                label[x1 - 1][y1] = 0;
                points[0] = x1;
            }
            //往右走
            if (x1 + 1 < graph.length && label[x1 + 1][y1] == 0 && graph[x1 + 1][y1] == value) {
                label[x1 + 1][y1] = 1;
                points[0] = x1 + 1;
                f2 = check(graph, label, points);
                label[x1 + 1][y1] = 0;
                points[0] = x1;
            }
            //往上走
            if (y1 - 1 >= 0 && label[x1][y1 - 1] == 0 && graph[x1][y1 - 1] == value) {
                label[x1][y1 - 1] = 1;
                points[1] = y1 - 1;
                f3 = check(graph, label, points);
                label[x1][y1 - 1] = 0;
                points[1] = y1;
            }
            //往下走
            if (y1 + 1 < graph.length && label[x1][y1 + 1] == 0 && graph[x1][y1 + 1] == value) {
                label[x1][y1 + 1] = 1;
                points[1] = y1 + 1;
                f4 = check(graph, label, points);
                label[x1][y1 + 1] = 0;
                points[1] = y1;
            }
            return f1 || f2 || f3 || f4;
        }
    }
    

    4.bfs及相关问题

    5.题解

  • 相关阅读:
    洛谷P1071 潜伏者
    2019BJFU 网站设计(孙俏-web前端开发)实验代码-181002222
    反思——P1307 数字反转
    洛谷P1067 多项式输出
    湖南大学第十五届程序设计竞赛(重现赛)
    2019河北省大学生程序设计竞赛(重现赛)
    2019BJFU C++实验习题(完结)
    配置android source 在ubuntu中编译环境
    Android屏幕保持唤醒状态
    Android richtext
  • 原文地址:https://www.cnblogs.com/cxynb/p/12877562.html
Copyright © 2020-2023  润新知