人工智能原理实验2(2)——罗马尼亚问题(贪婪搜索、A*搜索、BFS、DFS)

news2024/12/27 19:15:03

🧡🧡实验内容🧡🧡

在这里插入图片描述
根据上图以Zerind为初始状态,Bucharest为目标状态实现搜索,分别以贪婪搜索(只考虑直线距离)和A算法求解最短路径。 按顺序列出贪婪算法探索的扩展节点和其估价函数值,A算法探索的扩展节点和其估计值。

🧡🧡相关数据结构定义🧡🧡

状态表示的数据结构

每个城市代表一个状态,每个状态的属性主要包括:

  • 当前城市可从哪里来
  • 从起点到当前城市总花费的实际代价(代价函数g(x)
  • 当前城市到终点的直线距离(启发函数h(x)
    -在这里插入图片描述

状态扩展规则的表示

定义实际距离
主要是根据设定好的字典类型的变量,选择下一个城市,如下,例如Arad城市可以到达Zerind、Sibiu、Timisoara,后面数值为Arad到达它们的实际路程(也即图中线段上的数值)。
在这里插入图片描述
在这里插入图片描述

定义理想直线距离
直接用字典表示即可
在这里插入图片描述在这里插入图片描述

🧡🧡贪婪搜索求解🧡🧡

思想

首先了解估价函数f (x)=g(x)+h(x) 中,

  • f(x)为估价函数
  • g(x)为代价函数,代表从起点到当前x点的所花费的代价(距离)
  • h(x)为启发函数,代表当前x点到终点的估计代价(距离)
    当 不采用h(x)即g(x)=0时,f(x)=h(x),此时搜索为贪婪搜索,即每一次扩展均选择与终点离得最近(本题中h(x)为两城市的直线理想距离,而非线段上的真实距离)的城市

代码

# 贪婪搜索
import queue

class GBFS:
    def __init__(self, graph, heuristic, start, goal):
        self.graph = graph # 图
        self.heuristic = heuristic # 启发函数hn
        self.start = start # 起点
        self.goal = goal # 终点
        self.came_from = {} # 记录每个城市可以从哪里来(父节点)
        self.cost_so_far = {} # 从起点到该点总共花费的实际代价
        
    # 输出路径 和 对应的估计函数值
    def __show_path(self):
        current = self.goal
        path = [current] # 先导入终点city
        while current != self.start:  # 从终点回溯到起点city,加入所经city
            current = self.came_from[current]
            path.append(current)
        path = path[::-1]
        
        for i in range(len(path)-1):
            #\033[1;91m.....\033[0m为红色加粗的ANSI转义码
            print(f"=====================↓↓↓cur city: \033[1;91m{path[i]}\033[0m↓↓↓=====================") 
            for can_to_city in self.graph[path[i]].keys():
                print(f"can_to_city: \033[94m{can_to_city}\033[0m\t\t fn=\033[1;93m{self.heuristic[can_to_city]}\033[0m")
            print(f"选择fn最小的city: \033[1;92m{path[i+1]}\033[0m\n")
            
    
    def solve(self):
        frontier = queue.PriorityQueue()
        frontier.put((0, self.start)) # 将起点优先级设置为0,越小越优先
        self.came_from[self.start] = None # 父节点
        self.cost_so_far[self.start] = 0 # 从起点到cur city总共花费的fn
        close_=[]
        open_=[self.start]
        while not frontier.empty():

            current = frontier.get()[1]
            # 打印open_和close_表
#             print(f"open: {open_}  \nclose: {close_} \n")
#             open_.extend(list(self.graph[current].keys()))
#             open_.remove(current)
#             close_.append(current)
            
            if current == self.goal:
                self.__show_path()
                break

            for next in self.graph[current]: # 遍历current city 的next city
                new_cost = self.cost_so_far[current] + self.heuristic[next]
                if next not in self.cost_so_far or new_cost < self.cost_so_far[next]:
                    self.cost_so_far[next] = new_cost
                    priority = new_cost
                    frontier.put((priority, next))
                    self.came_from[next] = current


# 定义罗马尼亚地图
graph = {
    'Arad': {'Zerind': 75, 'Sibiu': 140, 'Timisoara': 118},
    'Zerind': {'Arad': 75, 'Oradea': 71},
    'Sibiu': {'Arad': 140, 'Oradea': 151, 'Fagaras': 99, 'Rimnicu Vilcea': 80},
    'Timisoara': {'Arad': 118, 'Lugoj': 111},
    'Oradea': {'Zerind': 71, 'Sibiu': 151},
    'Fagaras': {'Sibiu': 99, 'Bucharest': 211},
    'Rimnicu Vilcea': {'Sibiu': 80, 'Pitesti': 97, 'Craiova': 146},
    'Lugoj': {'Timisoara': 111, 'Mehadia': 70},
    'Mehadia': {'Lugoj': 70, 'Drobeta': 75},
    'Drobeta': {'Mehadia': 75, 'Craiova': 120},
    'Craiova': {'Drobeta': 120, 'Rimnicu Vilcea': 146, 'Pitesti': 138},
    'Pitesti': {'Rimnicu Vilcea': 97, 'Craiova': 138, 'Bucharest': 101},
    'Bucharest': {'Fagaras': 211, 'Pitesti': 101, 'Giurgiu': 90, 'Urziceni': 85},
    'Giurgiu': {'Bucharest': 90},
    'Urziceni': {'Bucharest': 85, 'Hirsova': 98, 'Vaslui': 142},
    'Hirsova': {'Urziceni': 98, 'Eforie': 86},
    'Eforie': {'Hirsova': 86},
    'Vaslui': {'Urziceni': 142, 'Iasi': 92},
    'Iasi': {'Vaslui': 92, 'Neamt': 87},
    'Neamt': {'Iasi': 87}
}

#  各城市到终点B的直线距离
heuristic = {
    'Arad': 366,
    'Zerind': 374,
    'Sibiu': 253,
    'Timisoara': 329,
    'Oradea': 380,
    'Fagaras': 176,
    'Rimnicu Vilcea': 193,
    'Lugoj': 244,
    'Mehadia': 241,
    'Drobeta': 242,
    'Craiova': 160,
    'Pitesti': 100,
    'Bucharest': 0,
    'Giurgiu': 77,
    'Urziceni': 80,
    'Hirsova': 151,
    'Eforie': 161,
    'Vaslui': 199,
    'Iasi': 226,
    'Neamt': 234
}

start = 'Zerind'
goal = 'Bucharest'

gbfs = GBFS(graph, heuristic, start, goal)
gbfs.solve()


运行结果

在这里插入图片描述
每次均选择h(x)(理想直线距离)小的城市,最终得出通过贪婪搜索算法搜出的最短路径为Zerind–>Arad–>Sibiu–>Fagaras

🧡🧡A*搜索求解🧡🧡

思想

估价函数:f(x) = g(x) + h(x)
即每一次扩展时,除了考虑选择离终点最近(直线距离h(x))的城市外,还考虑从起点城市到当前城市的实际距离(路段的真实权值g(x))

代码

# A*
import queue

class A_search:
    def __init__(self, graph, heuristic, start, goal):
        self.graph = graph # 图
        self.heuristic = heuristic # 启发函数hn
        self.start = start # 起点
        self.goal = goal # 终点
        self.came_from = {} # 记录每个城市可以从哪里来(父节点)
        self.cost_so_far = {} # 从起点到该点总共花费的实际代价

    # 输出路径 和 对应的估计函数值
    def __show_path(self):
        current = self.goal
        path = [current] # 先导入终点city
        while current != self.start:  # 从终点回溯到起点city,加入所经city
            current = self.came_from[current]
            path.append(current)
        path = path[::-1]
        
        for i in range(len(path)-1):
            #\033[1;91m.....\033[0m为红色加粗的ANSI转义码
            print(f"=====================↓↓↓cur city: \033[1;91m{path[i]}\033[0m↓↓↓=====================") 
            for can_to_city,cost in self.graph[path[i]].items():
                gn=self.cost_so_far[path[i]]  # 起点到cur city的实际代价
                c=cost  # cur city到next city的路途权值
                hn=self.heuristic[can_to_city] # next city到终点的直线距离
                fn=gn+c+hn
                print(f"can_to_city: \033[94m{can_to_city}\033[0m\t\t fn={gn}+{c}+{hn}=\033[1;93m{fn}\033[0m")
            print(f"选择fn最小的city: \033[1;92m{path[i+1]}\033[0m\n")
    
    def solve(self):
        frontier = queue.PriorityQueue()
        frontier.put((0, self.start)) # 将起点优先级设置为0,越小越优先
        self.came_from[self.start] = None # 父节点
        self.cost_so_far[self.start] = 0 # 从起点到该点总共花费的fn
        close_=[]
        open_=[self.start]
        while not frontier.empty():
            current = frontier.get()[1]
            # 打印open_和close_表
#             print(f"open: {open_}  \nclose: {close_} \n")
#             open_.extend(list(self.graph[current].keys()))
#             open_.remove(current)
#             close_.append(current)

            if current == self.goal:
                self.__show_path()
                break

            for next in self.graph[current]: # 遍历current city 的next city
                new_cost = self.cost_so_far[current] + self.graph[current][next] # 实际代价
                if next not in self.cost_so_far or new_cost < self.cost_so_far[next]:
                    self.cost_so_far[next] = new_cost
                    priority = new_cost + self.heuristic[next]  # 修改优先级为实际代价加上启发式函数值
                    frontier.put((priority, next))
                    self.came_from[next] = current


# 定义罗马尼亚地图
graph = {
    'Arad': {'Zerind': 75, 'Sibiu': 140, 'Timisoara': 118},
    'Zerind': {'Arad': 75, 'Oradea': 71},
    'Sibiu': {'Arad': 140, 'Oradea': 151, 'Fagaras': 99, 'Rimnicu Vilcea': 80},
    'Timisoara': {'Arad': 118, 'Lugoj': 111},
    'Oradea': {'Zerind': 71, 'Sibiu': 151},
    'Fagaras': {'Sibiu': 99, 'Bucharest': 211},
    'Rimnicu Vilcea': {'Sibiu': 80, 'Pitesti': 97, 'Craiova': 146},
    'Lugoj': {'Timisoara': 111, 'Mehadia': 70},
    'Mehadia': {'Lugoj': 70, 'Drobeta': 75},
    'Drobeta': {'Mehadia': 75, 'Craiova': 120},
    'Craiova': {'Drobeta': 120, 'Rimnicu Vilcea': 146, 'Pitesti': 138},
    'Pitesti': {'Rimnicu Vilcea': 97, 'Craiova': 138, 'Bucharest': 101},
    'Bucharest': {'Fagaras': 211, 'Pitesti': 101, 'Giurgiu': 90, 'Urziceni': 85},
    'Giurgiu': {'Bucharest': 90},
    'Urziceni': {'Bucharest': 85, 'Hirsova': 98, 'Vaslui': 142},
    'Hirsova': {'Urziceni': 98, 'Eforie': 86},
    'Eforie': {'Hirsova': 86},
    'Vaslui': {'Urziceni': 142, 'Iasi': 92},
    'Iasi': {'Vaslui': 92, 'Neamt': 87},
    'Neamt': {'Iasi': 87}
}

#  各城市到终点B的直线距离
heuristic = {
    'Arad': 366,
    'Zerind': 374,
    'Sibiu': 253,
    'Timisoara': 329,
    'Oradea': 380,
    'Fagaras': 176,
    'Rimnicu Vilcea': 192,
    'Lugoj': 244,
    'Mehadia': 241,
    'Drobeta': 242,
    'Craiova': 160,
    'Pitesti': 100,
    'Bucharest': 0,
    'Giurgiu': 77,
    'Urziceni': 80,
    'Hirsova': 151,
    'Eforie': 161,
    'Vaslui': 199,
    'Iasi': 226,
    'Neamt': 234
}

start = 'Zerind'
goal = 'Bucharest'

a = A_search(graph, heuristic, start, goal)
a.solve()

运行结果

在这里插入图片描述
每次考虑已花费的代价g和未来的估计代价h
解释一下 f 的计算
当前城市为Zerind时,到达Arad的估价代价f(Arad)=g(Arad)+h(Arad),而其中g(Arad)=g(Zerind)+cost(Zerind,Arad),因此f(Arad)=g(Zerind)+cost(Zerind,Arad)+h(Arad),又因为是起点,所以g(Zerind)为0。其中:g(Zerind)为到达Zerind已经走过的距离,cost(Zerind,Arad)为图中线段权值,即Zerind到Arad的实际距离,h(Arad)为Arad到终点的理想直线距离(上面的路径图中右侧的表格),同理对于城市Oradea也是一样的计算。
当前城市为Arad时,这里没有设置close表,因此它仍然可以选择返回到Zerind,这时由城市Arad到达Zerind城市的估计代价为 f(Zerind)=g(Zerind)+h(Zerind)=g(Arad)+cost(Arad,Zerind)+h(Zerind)。其他同理。

🧡🧡BFS、DFS求解🧡🧡

原理不多赘述了,直接上代码

BFS

# bfs
import queue

class BreadthFirstSearch:
    def __init__(self, graph, start, goal):
        self.graph = graph
        self.start = start
        self.goal = goal
        self.came_from = {}
    
    def __show_path(self):
        current = self.goal
        path = [current]
        while current != self.start:
            current = self.came_from[current]
            path.append(current)
        path = path[::-1]
        print("Path: ", " -> ".join(path))
    
    def solve(self):
        frontier = queue.Queue()
        frontier.put(self.start)
        self.came_from[self.start] = None
        
        while not frontier.empty():
            current = frontier.get()
            
            if current == self.goal:
                self.__show_path()
                break
            
            for next in self.graph[current]:
                if next not in self.came_from:
                    frontier.put(next)
                    self.came_from[next] = current


# 定义罗马尼亚地图
graph = {
    'Arad': {'Zerind': 75, 'Sibiu': 140, 'Timisoara': 118},
    'Zerind': {'Arad': 75, 'Oradea': 71},
    'Sibiu': {'Arad': 140, 'Oradea': 151, 'Fagaras': 99, 'Rimnicu Vilcea': 80},
    'Timisoara': {'Arad': 118, 'Lugoj': 111},
    'Oradea': {'Zerind': 71, 'Sibiu': 151},
    'Fagaras': {'Sibiu': 99, 'Bucharest': 211},
    'Rimnicu Vilcea': {'Sibiu': 80, 'Pitesti': 97, 'Craiova': 146},
    'Lugoj': {'Timisoara': 111, 'Mehadia': 70},
    'Mehadia': {'Lugoj': 70, 'Drobeta': 75},
    'Drobeta': {'Mehadia': 75, 'Craiova': 120},
    'Craiova': {'Drobeta': 120, 'Rimnicu Vilcea': 146, 'Pitesti': 138},
    'Pitesti': {'Rimnicu Vilcea': 97, 'Craiova': 138, 'Bucharest': 101},
    'Bucharest': {'Fagaras': 211, 'Pitesti': 101, 'Giurgiu': 90, 'Urziceni': 85},
    'Giurgiu': {'Bucharest': 90},
    'Urziceni': {'Bucharest': 85, 'Hirsova': 98, 'Vaslui': 142},
    'Hirsova': {'Urziceni': 98, 'Eforie': 86},
    'Eforie': {'Hirsova': 86},
    'Vaslui': {'Urziceni': 142, 'Iasi': 92},
    'Iasi': {'Vaslui': 92, 'Neamt': 87},
    'Neamt': {'Iasi': 87}
}

start = 'Zerind'
goal = 'Bucharest'

bfs = BreadthFirstSearch(graph, start, goal)
bfs.solve()

DFS

# dfs
class DepthFirstSearch:
    def __init__(self, graph, start, goal):
        self.graph = graph
        self.start = start
        self.goal = goal
        self.came_from = {}
    
    def __dfs(self, current):
        if current == self.goal:
            return [current]
        
        for next in self.graph[current]:
            if next not in self.came_from:
                self.came_from[next] = current
                path = self.__dfs(next)
                if path:
                    return [current] + path
        
        return None
    
    def __show_path(self, path):
        path = path[::-1]
        print("Path: ", " -> ".join(path))
    
    def solve(self):
        self.came_from[self.start] = None
        path = self.__dfs(self.start)
        if path:
            self.__show_path(path)
#         else:
#             print("No path found.")


# 定义罗马尼亚地图
graph = {
    'Arad': {'Zerind': 75, 'Sibiu': 140, 'Timisoara': 118},
    'Zerind': {'Arad': 75, 'Oradea': 71},
    'Sibiu': {'Arad': 140, 'Oradea': 151, 'Fagaras': 99, 'Rimnicu Vilcea': 80},
    'Timisoara': {'Arad': 118, 'Lugoj': 111},
    'Oradea': {'Zerind': 71, 'Sibiu': 151},
    'Fagaras': {'Sibiu': 99, 'Bucharest': 211},
    'Rimnicu Vilcea': {'Sibiu': 80, 'Pitesti': 97, 'Craiova': 146},
    'Lugoj': {'Timisoara': 111, 'Mehadia': 70},
    'Mehadia': {'Lugoj': 70, 'Drobeta': 75},
    'Drobeta': {'Mehadia': 75, 'Craiova': 120},
    'Craiova': {'Drobeta': 120, 'Rimnicu Vilcea': 146, 'Pitesti': 138},
    'Pitesti': {'Rimnicu Vilcea': 97, 'Craiova': 138, 'Bucharest': 101},
    'Bucharest': {'Fagaras': 211, 'Pitesti': 101, 'Giurgiu': 90, 'Urziceni': 85},
    'Giurgiu': {'Bucharest': 90},
    'Urziceni': {'Bucharest': 85, 'Hirsova': 98, 'Vaslui': 142},
    'Hirsova': {'Urziceni': 98, 'Eforie': 86},
    'Eforie': {'Hirsova': 86},
    'Vaslui': {'Urziceni': 142, 'Iasi': 92},
    'Iasi': {'Vaslui': 92, 'Neamt': 87},
    'Neamt': {'Iasi': 87}
}

start = 'Zerind'
goal = 'Bucharest'

dfs = DepthFirstSearch(graph, start, goal)
dfs.solve()

🧡🧡总结🧡🧡

比较运行效率

# cal_time
import time
import matplotlib.pyplot as plt
solve_list=['bfs','dfs','gbfs','a']
run_n=10000
show_time=[]
for solve in solve_list:
    cost_times=[]
    for i in range(run_n):
        start_time=time.time()
        globals()[solve].solve()
        end_time=time.time()
        cost_times.append(end_time - start_time)
    show_time.append(sum(cost_times)*1000/run_n)
    print(f"{solve} 算法的平均运行时间:{sum(cost_times)*1000/run_n} ms")
    

plt.bar(solve_list,show_time)

将程序运行10000次,统计BFS、DFS、贪婪算法、A*算法的平均运行时间如下:可以看见dfs在问题规模一般的情况的下效率非常高。
在这里插入图片描述

扩展思考:设计一个新的启发式函数,并分析该函数的可采纳性和优势(与启发式函数定义为“Zerind到Bucharest的直线距离”相比较)。
假设我们知道每个城市的人口数量,我们可以设计一个启发式函数,该函数将当前节点到目标节点的直线距离与两个城市的人口数量之比作为启发式值。即:fn = 当前节点和目标节点的人口数量之和/目标节点到当前节点的直线距离。

  • 可采纳性:这个启发式函数的可采纳性取决于实际问题的特征。如果人口密度对路径规划有重要影响,那么这个启发式函数是可采纳的。例如,人口密度可能会影响交通拥堵程度,从而影响出现体验。
  • 优势:与简单的直线距离相比,考虑人口数量可以使得搜索算法更倾向于经过人口稀疏的地区,从而在某些情况下找到更符合实际的路径。例如,如果把油费、乘车体验等等也作为路径选择的依据,那么可以避开人口密集的区域以减少交通拥堵,从而能更快更舒适地到达目的地点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1400671.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

读书笔记-《数据结构与算法》-摘要8[桶排序]

桶排序和归并排序有那么点点类似&#xff0c;也使用了归并的思想。大致步骤如下&#xff1a; 设置一个定量的数组当作空桶。Divide - 从待排序数组中取出元素&#xff0c;将元素按照一定的规则塞进对应的桶子去。对每个非空桶进行排序&#xff0c;通常可在塞元素入桶时进行插入…

springboot113健身房管理系统

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的健身房管理系统 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取…

文件操作和IO(1)

认识文件 先来认识狭义上的文件(存储在硬盘(磁盘)上).针对硬盘这种持久化的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,就类似办公桌上的一份份真实的文件一般. 注意:硬盘 ! 磁盘 磁盘属于…

【算法与数据结构】1049、LeetCode 最后一块石头的重量 II

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题需要得到石头之间两两粉碎之后的最小值&#xff0c;那么一个简单的思路就是将这堆石头划分成大小相…

HDFS节点故障的容错方案

HDFS节点故障的容错方案 1. NN高可用1.1 选主逻辑1.2 HA切换1.3 注意点1.3.1 fencing的处理1.3.2 健康状态的定义1.3.3 确保zk中的父节点存在1.3.4 确保NN的ID与IP保持一致 2. DN高可用2.1 感知DN节点异常2.1.1 NN感知DN心跳超时2.1.1 客户端链接DN异常 2.2 异常DN上的数据处理…

6.4.4释放音频

6.4.4释放音频 许多Flash动画里的音乐或歌曲非常好听&#xff0c;能不能在没有源文件的情况下把里面的声音文件取出来呢&#xff1f;利用Swf2VideoConverter2可以轻松做到这一点。 1&#xff0e;单击“添加”按钮&#xff0c;在弹出的下拉菜单中选择“添加文件”&#xff0c;…

蓝桥备战--分糖果OJ2928 贪心 分类讨论

题目&#xff1a; 思路&#xff1a; 首先排序(经验之谈) 分类讨论 我们要做到不重不漏的分类 代码&#xff1a; #include <iostream> #include <algorithm> using namespace std;const int N 1e6 10;char dist[N]; int n, x;int main() {string str;cin >…

以超市数据微案例-fineBI可视化分析

一、入门案例&#xff1a; 2.分析思路&#xff1a; 数据清晰界面中添加毛利额计算 **所以在新增步骤之后&#xff0c;必须点击保存并更新&#xff0c;否则可视化界面中无法使用最新的数据 4、数据可视化分析 1&#xff09;销售额最高的十大商品种类 为1-8月超市数据&#xff…

测试用例评审流程

1:评审的过程 A:开始前做好如下准备 1、确定需要评审的原因 2、确定进行评审的时机 3、确定参与评审人员 4、明确评审的内容 5、确定评审结束标准 6、提前至少一天将需要评审的内容以邮件的形式发送给评审会议相关人员。并注明详审时间、地点及偿参与人员等。 7、 在邮件中提醒…

每日一题——1295.统计位数为偶数的数字

方法一 个人方法&#xff1a; 想知道整数型数字有多少位&#xff0c;可以直接把数字转字符&#xff0c;看字符的长度就是数字的位数 var findNumbers function(nums) {let count0for(let num of nums){let strnumif(str.length%20) count}return count }; 消耗时间和内存情况…

【LLM-agent】function call功能、AgentTuning微调

note function call本质&#xff1a;准确识别用户的语义&#xff0c;将其转为结构化的指令&#xff0c;其中通过LLM理解指令和上下文判断需要调用哪个函数、抽取出input中函数所需的参数。是用户和界面交互方式产生质变的一个trick。所以为了提高模型准确识别和调用函数的能力…

HTML+JavaScript-01

说明 之前有一篇JavaWeb-JavaScript中只是简单介绍了一点JavaScript的内容&#xff0c;这篇笔记算是续写的&#xff0c;但是从01开始编号。 引入js文件 html、css、js俗称前端三剑客&#xff0c;一般都是分开写&#xff0c;先写框架、再写css、最后写js。因此在工程量大的情…

第36集《佛法修学概要》

请大家打开讲义第九十六面&#xff0c;我们讲到禅定的修学方便。 在我们发了菩提心&#xff0c;安住菩萨种性以后&#xff0c;我们开始操作六度的法门。六度的法门&#xff0c;它有两个不同的差别的内容&#xff0c;一种是成就我们的善业力&#xff0c;另外一种&#xff0c;是…

Unity中URP下的SimpleLit的 Lambert漫反射计算

文章目录 前言一、Lambert漫反射计算11、MixRealtimeAndBakedGI 函数有三个重载2、3号 调用了 2号3、1号调用了 SubtractDirectMainLightFromLightmap函数4、我们重点来看 Lambert漫反射的实现部分5、其余部分 二、Lambert漫反射计算21、LightingLambert 前言 在之前的文章中&…

电脑pdf如何转换成word格式?用它实现pdf文件一键转换

pdf转word格式可以用于提取和重用pdf文档中的内容&#xff0c;有时候&#xff0c;我们可能需要引用或引用pdf文档中的一些段落、表格或数据&#xff0c;通过将pdf转换为可编辑的Word文档&#xff0c;可以轻松地复制和粘贴所需内容&#xff0c;节省我们的时间&#xff0c;那么如…

windows下载安装ffmpeg最新版

windows环境搭建专栏&#x1f517;点击跳转 win系统环境搭建&#xff08;十六&#xff09;——windows下载安装ffmpeg最新版 文章目录 win系统环境搭建&#xff08;十六&#xff09;——windows下载安装ffmpeg最新版1.下载2.安装3.验证 1.下载 下载页面地址是https://ffmpeg.…

Windows WSL2 占用磁盘空间清理释放

目前工作中时常用到WSL2&#xff08;Ubuntu20.04&#xff09;&#xff0c;在使用一段时间后会发现WSL2所占用磁盘空间越来越多&#xff0c;体现在WSL2之上安装Linux分发对应的vhdx虚拟磁盘文件体积越来越大&#xff0c;会占用Windows自身空间&#xff0c;即使手动清理了Linux分…

计算机毕设thinkphp+mysql+_vue房屋租赁系统h3sem

运行环境:phpstudy/wamp/xammp等 开发语言&#xff1a;php 后端框架&#xff1a;Thinkphp5 前端框架&#xff1a;vue.js 服务器&#xff1a;apache 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat/phpmyadmin 房屋租赁管理系统有不同的用户角色。不同的用户权限对应不…

postgresql(Windows)初始化数据库教程

省流&#xff1a;本文章内容讲的是如何初始化postgresql数据库环境&#xff0c;前提是已经安装好postgresql数据库&#xff0c;安装步骤参考postgresql&#xff08;Windows&#xff09;安装教程 # 开始&#xff1a;安装postgresql-12.14-2-windows-x64.exe完成后进行初始化数据…

Java面试汇总——jvm篇

目录 JVM的组成&#xff1a; 1、JVM 概述(⭐⭐⭐⭐) 1.1 JVM是什么&#xff1f; 1.2 JVM由哪些部分组成&#xff0c;运行流程是什么&#xff1f; 2、什么是程序计数器&#xff1f;(⭐⭐⭐⭐) 3、介绍一下Java的堆(⭐⭐⭐⭐) 4、虚拟机栈(⭐⭐⭐⭐) 4.1 什么是虚拟机栈&…