zyz

人生如逆旅,我亦是行人|

转载请注明出处

Astar算法

A星算法简介 A*(A星)算法是一种基于格子(Grid)的寻路算法,用于从众多路径中,寻找一条从起点到终点代价最小的路径。基于格子也就是说会把地图看作是由 w*h 个格子组成的,因此寻得的路径也就是由一连串相邻的格子所组成的路径。 既然是要寻找代价最小的路径,那么遍历节点时,就不能盲目地遍历,而是挑那些 「最有可能代价很小」 的节点来运算。如何获得这种代价很小的节点呢?这就需要使用启发函数来计算每个节点的代价了(在A*中启发函数也被称为 估价函数 )。 一条路径的代价无非就是路径长度(不带权重时),可是当寻找路径时,该如何计算代价呢?那就是将代价分为两个方面: 已知代价。 即从起点到当前节点的路径长度。 未来可能会有的代价。 用 “猜” 的,假设当前节点到终点之间没有障碍,代价是多少。 那么我们就可以得到估价函数为:f(n) = g(n) + h(n),其中g(n)表示起点到格子n的代价,h(n)表示格子n到终点的代价,f(n)表示格子n的代价。 由于在EDA中,是使用曼哈顿距离来表示两点之间的距离,所以本文采用曼哈顿距离来计算代价。 知道启发函数是怎么回事之后我们就可以开始遍历节点了。从起点开始,计算其四周节点的代价,并把那些节点放到一个 「池子」 里面去,之后每次都从池子里面捞出来代价最小的节点,继续计算其周围节点的代价。 如果遍历到目标节点,或者池子空了之后,寻路就结束了。那么如何获得路径呢?我们从遍历的过程可以看出,节点加入到池子之前,我们知道这些加入到池子中的节点是来自于当前节点的,所以在加入池子之前将那些节点的父节点设为当前节点,等寻路到目标节点之后我们逐个节点遍历其父节点,就可以遍历完最短路径。 对于算法,有以下几点需要注意: 计算当前节点的周围节点的代价值时,如果需计算的节点原先就已经算过代价值,且当前算出来的代价值比原先的小,说明这个节点从当前节点过去路径会更短一些,应更新其父节点和代价值。 我们每次都是从「池子」中捞出代价最小的节点,所以用小根堆来实现「池子」是十分高效的。 综上所述,可以画出 A* 算法流程图: A星算法的实现 作者采用 C++ 来实现 A* 算法,代码已上传至此仓库

Linux学习笔记

软件安装与更新 在Linux下,一般用包管理器来安装软件,它能自动化地完成软件的安装、更新、配置和移除功能,优雅而快速。 软件包管理器的一个重要组成部分是软件仓库。软件仓库是收藏了互联网上可用软件包(应用程序)的图书馆,里面往往包含了数万个可供下载 和安装的可用软件包。 有了软件仓库,我们不需要手动下载大量的软件包再通过包管理器安装。只需要知道软件在软件仓库中的名称,即可让包管理器从网络中抓取到相应的软件包到本地,自动进行安装。 但是与应用商店相比,使用包管理器安装需要预先知道所需软件在软件仓库中的对应包名,和应用商店相比无法进行模糊搜索(不过你也可以在包管理器官网上进行查找包名,再通过包管理器安装)。 作者使用的是Ubuntu系统,Ubuntu下默认的包管理器为apt,所有后面的讲解以apt为例。 使用包管理器系统安装 搜索 安装前,先在浏览器中搜索所需的软件,查找包名,再使用 apt search package_name 命令搜索软件仓库,查看对应的包名是否在软件仓库中(这步可跳过,只要知道要安装的软件包名即可)。 安装 找到要安装的软件的包名后,使用命令 apt install package_name 进行安装。 PS: 如果提示当前用户无安装软件权限,则在命令前加上 sudo,即 sudo apt install package_name,输入此命令后会要求用户输入密码(输入的密码不会在终端显示)。 官方软件源镜像 通过 apt 安装的软件都来源于相对应的软件源,每个 Linux 发行版一般都带有官方的软件源,在官方的软件源中已经包含了丰富的软件,apt 的软件源列表在 /etc/apt/sources.list 下。 Ubuntu 官方源位于国外,往往会有速度与延迟上的限制,可以通过修改官方源为其镜像实现更快的下载速度。镜像缓存了官方源中的软件列表,与官方源基本一致。 修改官方源为镜像步骤 本例以修改官方源为 USTC Mirror 为例。注意:在操作前请做好备份。 一般情况下,/etc/apt/sources.list 下的官方源地址为 http://archive.ubuntu.com/ ,我们只需要将其替换为 http://mirrors.ustc.edu.cn 即可。 如果你使用 Ubuntu 图形安装器安装,默认的源地址通常不是 http://archive.ubuntu.com/ , 而是 http://<country-code>.archive.ubuntu.com/ubuntu/ ,如 http://cn.archive.ubuntu.com/ubuntu/,同样也将其替换为 http://mirrors.ustc.edu.cn 即可。 可以使用如下命令: $ sudo sed -i 's|//.*archive.ubuntu.com|//mirrors.ustc.edu.cn|g' /etc/apt/sources.list 当然也可以直接使用 vim、nano 等文本编辑器进行修改。

VsCode推荐插件

Better C++ Syntax 该插件主要作用是提供 C++ 语法高亮 Bookmarks 该插件主要作用是允许用户在代码中添加书签,以便快速跳转到这些特定位置。这个插件对于需要在大型项目中导航和跟踪重要代码段的开发者来说非常有用。 该插件常用快捷键为: 添加书签:Ctrl+Alt+K 删除书签:将光标放在带有书签的行上,然后使用 Ctrl+Alt+J 切换书签:Ctrl+Alt+Q可以在书签之间切换,如果当前行有书签,则会删除它。 跳转到下一书签:Ctrl+Alt+L 跳转到上一书签:Shift+Ctrl+Alt+L C/C++ 该插件主要作用是提供了一系列的工具和功能,例如代码分析功能、代码格式化功能、代码提示等。 CMake 该插件主要作用是CMake语法高亮、CMake代码自动补全。 CMake Tools 该插件主要作用是提供各种CMake编译相关的小工具,包括在底部状态栏显示一些快捷工具。 cmake-format 该插件的主要作用是格式化 CMakeLists.txt 文件,使其保持一致和可读性。安装此插件前,需要先安装cmake-format工具。 Code Runner 该插件的主要作用是运行选定的代码片段。 该插件常用快捷键为: 运行选定代码 Ctrl+Alt+N 或 直接点击右上角的三角形 或 点击右键菜单中的 Run Code 停止正在运行的代码 Ctrl+Alt+M 或 点击右键菜单中的 Stop Run Code 插件详细说明地址 Diff 该插件的主要作用是比较两个文件的不同之处,直接在资源管理窗口中选择两个要比较的文件,将会直接显示比较结果。 Error Lens 该插件的主要作用是将代码中存在的问题突出显示(包括错误、警告和语法问题),它不仅在代码行尾显示问题,而且会在整行进行高亮,使得诊断信息更加明显。 GitLens 该插件的主要作用是可以更方便地在VsCode中进行Git相关操作,该插件的使用可看此视频了解。 PS: 建议能够熟练使用Git命令后再使用此插件,Git的学习可看此教程。 GitHub Copilot 该插件的主要作用是辅助编码。该插件是GitHub的AI编码工具,能根据注释、函数名、函数参数编写代码。该插件的详细介绍可看此文章。 PS: 该插件需要进行GitHub学生认证才能免费使用,可参考此教程。 Include Autocomplete 该插件的主要作用是提供编写 C++ #include 语句时自动补全功能 Markdown All in One 和 Markdown Preview Enhanced 这两个插件都是用于帮助编写Markdown文件

C++学习笔记

前言 由于笔者具备一定的C语言基础,所以在本文中对于C语言的语法不再会进行赘述,主要专注与C++语法。为了更好的学习C++,笔者找了一些题目来进行练习,所有题目与题解均可在此仓库找到。 本学习笔记适用于 「具备一定C语言基础,想要使用C++来编写代码」 的读者。 本文阅读指南: 在看过示例代码后,一定要编写一个自己的示例代码 或 自己动手重写一遍。 标红的注意内容一定要仔细看!!! 一定要做上面仓库中的题!!!一定要做上面仓库中的题!!!一定要做上面仓库中的题!!! 好的命名能够提高代码的可读性,本文从类章节开始采用以下命名规范: 局部变量名单词之间使用下划线隔开; 类的变量成员用下划线作为前缀如 _file_name; 类的函数名使用驼峰类型;如doSomething(); 类的成员存取使用 如get_file_name() set_file_name(); 类名是PASCAL风格,即首字母大写 如MyClass; 常量用k作为前缀后面是PASCAL风格如 kFileName; 全局变量用g作为前缀后面是PASCAL风格如 gFileName; 宏定义全大写,中间用下划线隔开 FILE_NAME。 从C到C++ 本章节主要介绍一些C++的比较重要特性,例如如何申请和释放内存空间、bool和string类型、命名空间等。这些新特性可以给我们编程提供遍历,提高开发效率。 布尔类型(bool) 在C语言中,没有"真"与"假"的数据类型,我们通常使用一个整形变量的值来表示真假,其值为 1 表示真,为 0 表示假。以下为一个例子: 1 2 3 4 5 6 7 8 int IsOddNum(int n) //判断一个数是否是奇数 { int flag; if(n % 2 == 0) flag = 0; else flag = 1; return flag; } 然而,这种做法有几个缺点: 可读性差: 使用整数来表示布尔值可能会让代码的可读性降低,因为读者需要记住0和非0值的含义。 存在类型安全问题: 整数可以进行算术运算,这可能导致意外的类型转换和错误。 语义不明确: 整数类型的使用没有明确表达出变量的布尔语义。 所以,C++提供了 bool 类型来表示真假,该类型的变量只有 true 和 false 两种取值。那么上面的例子则可改为:

IEDA点工具运行前环境变量设置

脚本创建 在单独运行点工具前必须配置对应的环境变量,在iEDA目录/iEDA/scripts/design/sky130_gcd下使用命令touch创建一个.sh脚本,内容如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #!/bin/bash CURRENT_DIR="(pwd)"exportCONFIGDIR="(pwd)" export CONFIG_DIR="CURRENT_DIR/iEDA_config" export RESULT_DIR="CURRENTDIR/result/mytestresult"exportTCLSCRIPTDIR="CURRENT_DIR/result/my_test_result" export TCL_SCRIPT_DIR="CURRENT_DIR/script" export NETLIST_FILE="CURRENTDIR/result/verilog/gcd.v"exportFOUNDRYDIR="CURRENT_DIR/result/verilog/gcd.v" export FOUNDRY_DIR="CURRENT_DIR/../../foundry/sky130" export SPEF_FILE="CURRENTDIR/../../foundry/sky130/spef/gcd.spef"exportSDCFILE="CURRENT_DIR/../../foundry/sky130/spef/gcd.spef" export SDC_FILE="CURRENT_DIR/../../foundry/sky130/sdc/gcd.sdc" export DESIGN_TOP="gcd" export DIE_AREA="0.0 0.0 149.96 150.128" export CORE_AREA="9.996 10.08 139.964 140.048" echo "CONFIG_DIR set to: CONFIGDIR"echo"RESULTDIRsetto:CONFIG_DIR" echo "RESULT_DIR set to: RESULT_DIR" echo "TCL_SCRIPT_DIR set to: TCLSCRIPTDIR"echo"NETLISTFILEsetto:TCL_SCRIPT_DIR" echo "NETLIST_FILE set to: NETLIST_FILE" echo "FOUNDRY_DIR set to: FOUNDRYDIR"echo"SPEFFILEsetto:FOUNDRY_DIR" echo "SPEF_FILE set to: SPEF_FILE" echo "SDC_FILE set to: SDCFILE"echo"DESIGNTOPsetto:SDC_FILE" echo "DESIGN_TOP set to: DESIGN_TOP" echo "DIE_AREA set to: DIEAREA"echo"COREAREAsetto:DIE_AREA" echo "CORE_AREA set to: CORE_AREA" 点工具运行 运行点工具前,在当前窗口使用命令 source 脚本名.

322. 零钱兑换

题目描述(力扣): 什么是最优子结构 最优子结构指的是,问题的最优解包含子问题的最优解。反过来说就是,可以通过子问题的最优解,推导出问题的最优解。要符合「最优子结构」,子问题间必须互相独立。 比如说,假设你考试,每门科目的成绩都是互相独立的。你的原问题是考出最高的总成绩,那么你的子问题就是要把语文考到最高,数学考到最高…… 为了每门课考到最高,你要把每门课相应的选择题分数拿到最高,填空题分数拿到最高…… 当然,最终就是你每门课都是满分,这就是最高的总成绩。 得到了正确的结果:最高的总成绩就是总分。因为这个过程符合最优子结构,「每门科目考到最高」这些子问题是互相独立,互不干扰的。 但是,如果加一个条件:你的语文成绩和数学成绩会互相制约,不能同时达到满分,数学分数高,语文分数就会降低,反之亦然。 这样的话,显然你能考到的最高总成绩就达不到总分了,按刚才那个思路就会得到错误的结果。因为「每门科目考到最高」的子问题并不独立,语文数学成绩户互相影响,无法同时最优,所以最优子结构被破坏。 思路: 题目说明了每种硬币数量无限,所以该问题具有最优子结构,可以用动态规划来解决。确定好用动态规划来解决后,先确定dp数组的意义,这里dp[i]存储的值就是总金额为i的最优解。接下来最重要的事情就是找到状态转移方程,dp[0] = 0,当amount大于0时,我们只需遍历给出的coins数组找到 dp[amount - coin_value] + 1 中的最小值即可(避免越界,需要先判断coin_value是否小于amount),加一是因为要加上一个面值为coin_value的硬币。 代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution { public: int coinChange(vector<int>& coins, int amount) { vector<int> dp(amount + 1, INT_MAX - 1); //初始化dp数组,初始值为INT_MAX - 1是因为后面有dp[i - value] + 1操作,需要避免整形溢出 dp[0] = 0; //已知的最优解 for(int i = 1; i <= amount; i++) { for(int value : coins) //遍历每种硬币 { if(i - value < 0) continue; //进行判断是为了避免越界 dp[i] = min(dp[i], dp[i - value] + 1); //找到总金额为 i 时的最优解 } } return dp[amount] == (INT_MAX - 1) ?

543. 二叉树的直径

题目描述(力扣): 思路: 首先理解二叉树的直径指的是二叉树中任意两个节点之间的路径长度的最大值(最长直径不一定经过根节点)。想要找到二叉树的直径,就需要遍历每个节点,依次计算每个节点的左右子树深度之和,其中的最大值就是二叉树的直径。因为二叉树的直径大多数情况下就是根节点下的左右子树深度之和,但存在直径不经过根节点的情况,所以需要遍历每个节点,计算以该节点为根的二叉树的直径,然后取计算结果中的最大值。根据前面的分析,我们需要计算左右子树深度之和,这就需要左右子树的信息,所以选择后序遍历。 代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: int diameterOfBinaryTree(TreeNode* root) { maxDepth(root); return maxDia; } int maxDepth(TreeNode* root) { if(root == nullptr) return 0; int lefth_h = maxDepth(root->left); int right_h = maxDepth(root->right); int Dia = lefth_h + right_h; //计算当前二叉树的直径 maxDia = max(maxDia, Dia); return lefth_h > right_h?
0%