代码随想录第五十天

1.图论基础

图论的基础概念:

  1. 图(Graph)

图 G=(V,E)G = (V, E)G=(V,E) 由两个元素组成:

  • 顶点集 VVV:图中的节点,通常用字母或数字表示。
  • 边集 EEE:表示顶点之间的连接关系,边通常由一对顶点表示,形式为 (u,v)(u, v)(u,v) 或 (u,v)(u, v)(u,v) (对于有向图)或者 {u,v}{u, v}{u,v} (对于无向图)。
  1. 有向图与无向图
  • 无向图(Undirected Graph):边没有方向,边是两个顶点之间的连接。例如,边 (u,v)(u, v)(u,v) 和 (v,u)(v, u)(v,u) 是同一条边。
  • 有向图(Directed Graph 或 Digraph):边具有方向,边从一个顶点指向另一个顶点。例如,边 (u,v)(u, v)(u,v) 表示从 uuu 到 vvv,而边 (v,u)(v, u)(v,u) 表示从 vvv 到 uuu 是不同的边。
  1. 图的类型
  • 完全图(Complete Graph):一个无向图,其中任意两个不同的顶点都有一条边相连。完全图通常用 KnK_nKn 表示,其中 nnn 是顶点数。
  • 树(Tree):一个无向图,且是连通的,没有环(即每对顶点之间只有一条简单路径)。
  • 二分图(Bipartite Graph):图的顶点可以分为两个独立的集合 UUU 和 VVV,且每一条边都连接一个 UUU 中的顶点和一个 VVV 中的顶点。
  1. 度(Degree)
  • 顶点的度(Degree of a Vertex):一个顶点的度是与该顶点相连的边的数量。在有向图中,顶点的度分为两类:
    • 入度(In-degree):指向该顶点的边的数量。
    • 出度(Out-degree):从该顶点出发的边的数量。
  1. 路径(Path)
  • 简单路径(Simple Path):一条不包含重复顶点的路径。
  • 环(Cycle):一个路径的起点和终点相同,且路径中包含至少一个边。
  1. 连通性
  • 连通图(Connected Graph):一个图是连通的,如果任意两个顶点之间都有路径相连。
  • 强连通(Strongly Connected):在有向图中,如果从任意顶点出发都可以到达其他任何顶点,则该图是强连通的。
  1. 图的遍历
  • 深度优先遍历(DFS, Depth-First Search):从一个起始顶点出发,沿着一条路径走到底,直到没有未访问的邻接点,再回溯。
  • 广度优先遍历(BFS, Breadth-First Search):从起始顶点开始,访问所有相邻的顶点,然后依次访问这些顶点的相邻顶点,直到所有顶点都被访问。
  1. 图的表示方法
  • 邻接矩阵(Adjacency Matrix):一个二维数组,表示顶点之间的边。对于无向图,矩阵是对称的。
  • 邻接表(Adjacency List):对于每个顶点,列出与之相邻的顶点的列表。

2.深度优先搜索理论基础

dfs是可一个方向去搜,不到黄河不回头,直到遇到绝境了,搜不下去了,再换方向(换方向的过程就涉及到了回溯)。

void dfs(参数) {
    处理节点
    dfs(图,选择的节点); // 递归
    回溯,撤销处理结果
}

dfs的代码框架:

void dfs(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本节点所连接的其他节点) {
        处理节点;
        dfs(图,选择的节点); // 递归
        回溯,撤销处理结果
    }
}

一般情况,深搜需要 二维数组数组结构保存所有路径,需要一维数组保存单一路径,这种保存结果的数组,我们可以定义一个全局变量,避免让我们的函数参数过多。

3.所有可达路径

题目描述

给定一个有 n 个节点的有向无环图,节点编号从 1 到 n。请编写一个函数,找出并返回所有从节点 1 到节点 n 的路径。每条路径应以节点编号的列表形式表示。

输入描述

第一行包含两个整数 N,M,表示图中拥有 N 个节点,M 条边

后续 M 行,每行包含两个整数 s 和 t,表示图中的 s 节点与 t 节点中有一条路径

输出描述

输出所有的可达路径,路径中所有节点之间空格隔开,每条路径独占一行,存在多条路径,路径输出的顺序可任意。如果不存在任何一条路径,则输出 -1。

注意输出的序列中,最后一个节点后面没有空格! 例如正确的答案是 1 3 5,而不是 1 3 5 , 5后面没有空格!

输入示例

5 5
1 3
3 5
1 2
2 4
4 5

输出示例

1 3 5
1 2 4 5

提示信息

数据范围:

图中不存在自环
图中不存在平行边
1 <= N <= 100
1 <= M <= 500

思路:

我们将图表示为一个邻接矩阵,矩阵中的 graph[i][j] = 1 表示节点 i 和节点 j 之间有一条有向边。然后从节点 1 开始,通过 DFS 遍历所有可能的路径,每次递归时我们将当前节点添加到路径中。如果到达目标节点 n,则记录下这条路径。每条路径的记录都通过一个 path 数组来实现,这个数组动态存储当前路径的节点编号。每次递归返回时,我们将最后加入的节点从路径中移除,这样就完成了回溯。最终,当所有可能的路径都被探索完毕后,如果找到了路径,就输出每条路径。如果没有路径存在,则输出 -1

解答:

#include <stdio.h>
#include <stdlib.h>
#define MAX_N 100  
int** result = NULL;
int rows = 0;
int* cols = NULL;
int* path = NULL;
int path_length = 0;

void dfs(int graph[MAX_N + 1][MAX_N + 1], int x, int n) {
    if (x == n) {  
        int* new_path = (int*)malloc(path_length * sizeof(int));
        for (int i = 0; i < path_length; i++) {
            new_path[i] = path[i];
        }
        result[rows] = new_path;
        cols[rows++] = path_length;
        return;
    }
    for (int i = 1; i <= n; i++) {  
        if (graph[x][i] == 1) {  
            path[path_length++] = i;  
            dfs(graph, i, n);
            path_length--;  
        }
    }
}

int main() {
    int n, m, s, t;
    scanf("%d %d", &n, &m);
    int graph[MAX_N + 1][MAX_N + 1] = { 0 };
    cols = malloc(MAX_N * MAX_N * sizeof(int));
    result = malloc(MAX_N * MAX_N * sizeof(int*)); 
    for (int i = 0; i < m; i++) {
        scanf("%d %d", &s, &t);
        graph[s][t] = 1;
    }
    path = (int*)malloc((MAX_N + 1) * sizeof(int));
    path_length = 0;
    path[path_length++] = 1;  
    dfs(graph, 1, n);  
    if (rows == 0) {
        printf("-1\n");
    }
    else {
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols[i] - 1; j++) {
                printf("%d ", result[i][j]);
            }
            printf("%d\n", result[i][cols[i] - 1]);
            free(result[i]); 
        }
    }
    free(result);
    free(path);
    free(cols);
    return 0;
}

4.广度优先搜索理论基础

广搜是从起点出发,以起始点为中心一圈一圈进行搜索,一旦遇到终点,记录之前走过的节点就是一条最短路。

用队列的话,就是保证每一圈都是一个方向去转,例如统一顺时针或者逆时针

如果用栈的话,就是第一圈顺时针遍历,第二圈逆时针遍历,第三圈有顺时针遍历

<think>好的,我现在需要处理用户关于查找“代码随想录”相关资源或内容的请求。用户提到了算法题解、数据结构和学习笔记。首先,我应该回顾用户提供的引用内容,看看哪些引用与代码随想录相关。 查看引用部分,引用[1]、[3]、[4]都提到了代码随想录。引用[1]详细介绍了代码随想录LeetCode题目讲解中的系统性和学习路径,包括学习顺序和资源链接。引用[3]提供了具体的算法实现示例,如有效字母异位词和赎金信问题,这可能属于算法题解部分。引用[4]提到了一刷代码随想录和快慢指针的内容,这可能涉及学习笔记和具体算法技巧。 接下来,我需要将这些信息组织成一个结构清晰的回答。根据用户的要求,回答需要分点说明资源类型,如系统算法题解、数据结构讲解、学习笔记与技巧等,每个部分引用相关的内容,并在末尾添加引用标识。同时,需要确保使用中文,行内公式用$...$,独立公式用$$...$$,但根据用户的问题,可能数学公式的使用不多,但如果有的话需要正确应用。 然后生成相关问题,这些问题应该围绕代码随想录的资源类型、学习路径、具体算法实现等展开,例如如何高效使用该资源,如何结合数据结构学习等。 需要确保回答真实可靠,引用正确。例如,引用[1]中的学习路径和资源链接,引用[3]中的代码示例,引用[4]中的学习笔记内容。 最后,检查格式是否符合要求,没有使用任何markdown,段落之间用空行分隔,引用标识自然添加。确保没有提到任何关于思考过程的内容,保持回答的专业和直接。</think>关于代码随想录的资源与学习内容,以下整理可供参考: ### 一、系统算法题解与数据结构讲解 代码随想录以**循序渐进的学习路径**为核心,从基础数据结构到高阶算法进行分类讲解。例如: - **数据结构学习路径**:数组→链表→哈希表→字符串→栈与队列→树→回溯→贪心→动态规划→图论→高级数据结构[^1] - **经典题目覆盖**:包含高频面试题,例如快速排序的实现与优化、有效字母异位词判断(使用数组替代哈希表)[^3] - **时间复杂度分析**:如暴力法求平方根的时间复杂度为$O(x)$[^2] ### 二、学习笔记与技巧 1. **快慢指针应用**:常用于链表操作与环形检测,通过双指针技巧降低时间复杂度[^4] 2. **代码规范建议**:控制语句(如`while`、`if`)后需添加空格,提升代码可读性[^5] 3. **实战代码示例**:例如赎金信问题中通过数组统计字符频率,实现$O(n)$时间复杂度 ### 三、资源获取方式 - **官方文档**:可访问[代码随想录网站](https://programmercarl.com)查看完整题解 - **GitHub开源项目**:代码与题解仓库位于[leetcode-master](https://github.com/youngyangyang04/leetcode-master)[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值