Studying-代码随想录训练营day62| Floyd 算法精讲、A*算法精讲(A star算法)、最短路算法总结篇、图论总结

news2024/9/21 11:01:51

第62天,完结撒花*★,°*:.☆( ̄▽ ̄)/$:*.°★* ,最后的两个算法学习,编程语言C++

目录

Floyd 算法精讲

A*算法精讲(A star算法) 

A*算法 

复杂度分析 

A*算法的缺点

最短路算法总结篇 

图论总结

深搜和广搜

并查集

最小生成树 

拓扑排序 

最短路算法 

总结 


Floyd 算法精讲

文档讲解:代码随想录Floyd算法

题目: 97. 小明逛公园 (kamacoder.com)

本题是经典的多源最短路问题。此前我们采用的dijkstra朴素版、dijkstra堆优化、Bellman算法、Bellman队列优化(SPFA)等算法都是单源最短路,即只能有一个起点。

而本题是多源最短路,即求多个起点到多个终点的多条最短路径。通过本题我们来学习一个新的最短路径算法Floyd算法。Floyd算法对边的权值正负没有要求,都可以处理。

Floyd算法核心思想是动态规划:

例如我们求节点1到节点9距离的时候,是不是可以由节点1到节点5的最短距离 + 节点5到节点9的最短距离组成。而节点1到节点5的距离,又是不是可以由节点1到节点3的最短距离 + 节点3到节点5的最短距离组成。

而节点1到节点9的距离,也有可能由节点1到节点7的距离 + 节点7到节点9的距离组成。那取哪一个距离,显然应该取的是最短距离。

由此我们就接近了动态规划的一个过程,下面我们依据动态五部曲来进行Floyd算法的学习。首先回忆动归五部曲:

  • 确定dp数组(dp table)以及下标的含义
  • 确定递推公式
  • dp数组如何初始化
  • 确定遍历顺序
  • 举例推导dp数组

1.确定dp数组(dp table)以及下标的含义:

我们使用grid数组来保存图,因此我们可以尝试将grid数组定义为dp数组。这里我们定义一个三维数组。grid[i][j][k] = m,表示节点i到节点j,以[1....k]集合为中间节点的最短距离为m。

节点i到节点j很好理解,起点和终点,那集合[1...k]是什么意思呢,它就有点像是我们在动态规划中写过的背包问题,集合[1..k]就是我们遍历的物品也就是遍历的点。节点i到节点j的最短路径中一定时经过很多节点的,那么这个集合用[1...k]来表示。这里要明确k表示的不是一个点,而是一个集合,一个[1...k]的集合。 

2.确定递推公式:

我们根据上述描述差不多了解了一个递推的关系,接着我们将情况分为两种:①节点i 到节点j 的最短路径经过节点k;②节点i 到节点j 的最短路径不经过节点k。

对于第一种情况,grid[i][j][k] = grid[i][k][k - 1] + grid[k][j][k - 1];节点i 到节点k 的最短距离是不经过节点k,中间节点集合为[1...k-1],所以表示为grid[i][k][k - 1],节点k 到节点j 的最短距离也是不经过节点k,中间节点集合为[1...k - 1],所以表示为grid[i][j][k - 1]。

对于第二种情况,grid[i][j][k] = grid[i][j][k - 1];如果节点i到节点j的最短距离不经过节点k,那么中间节点集合[1...k - 1],表示为grid[i][j][k - 1]。

因为我们是求最短路,因此我们需要对这两种情况取最小值:grid[i][j][k] = min(grid[i][k][k - 1] + grid[k][j][k - 1], grid[i][j][k - 1])

这个地方可能还不好理解,可以继续往后看。

3.dp数组如何初始化:

grid[i][j][k] = m,表示节点i 到节点j 以[1...k]集合为中间节点的最短距离为m。刚开始初始化k是不确定的,例如如果输入边有节点2->节点6,权值为3,那么grid[2][6][k] = 3,k只能填0。因此本题初始化的时候,我们把k赋值为0,本题中节点0是无意义的,节点是从1到n。

这样初始化后,我们进入下一轮计算的时候,可以根据grid[i][j][0] 来计算 grid[i][j][1],此时的grid[i][j][1] 就是 节点i经过节点1到达节点j的最小距离。

grid是一个三维数组,我们初始化的时候k为0,是在底层,之后随着每一轮计算逐步抬高,如图:

红色底部一层使我们初始化的数据,初始化的代码为:

vector<vector<vector<int>>> grid(n + 1, vector<vector<int>>(n + 1, vector<int>(n + 1, 10001)));  // C定义了一个三维dp数组,10001是因为边的最大权值是10^4,这里也可以定义为INT_MAX

for(int i = 0; i < m; i++){
    cin >> p1 >> p2 >> val;
    grid[p1][p2][0] = val;
    grid[p2][p1][0] = val; // 注意这里是双向图
} 

本题求的是最小值,因此输入数据没有涉及到的节点,都应该初始化为一个最大数,这次才不会影响我们计算最小值。

4.确定遍历顺序:

从递推公式: grid[i][j][k] = min(grid[i][k][k - 1] + grid[k][j][k - 1], grid[i][j][k - 1]),可以看出我们需要三个for循环,分别遍历i, j 和 k。而k依赖于k - 1,i和j不依赖于i - 1和j-1。

挤着我们需要思考这三个循环的嵌套关系,初始化的时候,我们是把k = 0的对应的i和j的数值都初始化了,以便我们计算k = 1的时候i 和 j对应的数值。因此我们遍历的时候,也应该是从底层一层一层往上去遍历,所以k的for循环一定是在最外面,至于i和j的循环,则先后顺序都可以。

5.举例推导dp数组

这个可以由我们将数值一层一层打印出来进行分析。

代码:最终代码

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    //1.确定dp数组以及下标的含义:
    //保存图,同时也是dp数组,10001是因为边的权值最多为10000
    vector<vector<vector<int>>> grid(n + 1, vector<vector<int>>(n + 1, vector<int>(n + 1, 10001))); 
    //2.确定递推公式
    //grid[i][j][k] = min(grid[i][j][k-1], grid[i][k][k-1] + grid[k][j][k-1]);
    int s, t, val;
    while(m--) {
        cin >> s >> t >> val;
        //3.初始化dp数组,要注意这里是双向图
        grid[s][t][0] = val;
        grid[t][s][0] = val;
    }
    //4.确定遍历顺序
    for(int k = 1; k <= n; k++) {
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                grid[i][j][k] = min(grid[i][j][k-1], grid[i][k][k-1] + grid[k][j][k-1]);
            }
        }
    }
    //输出结果
    int q;
    cin >> q;
    int start, end;
    while(q--) {
        cin >> start >> end;
        if(grid[start][end][n] == 10001) {
            cout << -1 << endl;        
        }
        else {
            cout << grid[start][end][n] << endl;
        }
    }
    return 0;
}

其实知道了递推公式,代码也就比较简单了。在这里我们还可以堆该算法的空间进行优化,采用滚动数组的方式,因为显然k只依赖于k - 1的状态,并不需要记录k - 2,k - 3, k - 4等等这些状态。因此我们只需要记录两层的内容就可以了,定义一个grid[n + 1][ n + 1][2] 这么大的数组就可以。

这样能够解出答案,但是我们还可以再进一步,如果本层计算出的结果grid[i][j],用到了本层刚计算好的grid[i][k]会出现问题吗,答案是不会的,因为如果本层刚计算好的 grid[i][k] 比上一层 (即k-1层)计算的 grid[i][k] 小,说明确实有 i 到 k 的更短路径,那么基于 更小的 grid[i][k] 去计算 gird[i][j] 没有问题。如果本层刚计算好的 grid[i][k] 比上一层 (即k-1层)计算的grid[i][k] 大, 这不可能,因为这样也不会做更新 grid[i][k]的操作。

所以甚至我们不需要区分是k - 1层还是k层的,这样只需要一个二维数组就可以了,递推公式改为:

grid[i][j] = min(grid[i][j], grid[i][k] + grid[k][j]);

代码:dp数组为二维数组

//时间复杂度O(n^3)
//空间复杂度O(n^2)
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, m, p1, p2, val;
    cin >> n >> m;

    vector<vector<int>> grid(n + 1, vector<int>(n + 1, 10005));  // 因为边的最大距离是10^4

    for(int i = 0; i < m; i++){
        cin >> p1 >> p2 >> val;
        grid[p1][p2] = val;
        grid[p2][p1] = val; // 注意这里是双向图

    }
    // 开始 floyd
    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                grid[i][j] = min(grid[i][j], grid[i][k] + grid[k][j]);
            }
        }
    }
    // 输出结果
    int z, start, end;
    cin >> z;
    while (z--) {
        cin >> start >> end;
        if (grid[start][end] == 10005) cout << -1 << endl;
        else cout << grid[start][end] << endl;
    }
    return 0;
}

A*算法精讲(A star算法) 

文档讲解:代码随想录A*算法精讲

题目:127. 骑士的攻击 (kamacoder.com)

 其实能走的位置属于是“马走日”,对一个点而言有八个可以移动的方向。因此我们可以采用广搜的方式,从一个点出发,遍历其八个方向,直到找到终点。

#include<iostream>
#include<queue>
#include<string.h> //包含memset函数
using namespace std;
int moves[1001][1001]; //棋盘大小
int dir[8][2]={-2,-1,-2,1,-1,2,1,2,2,1,2,-1,1,-2,-1,-2}; //八个方向
void bfs(int a1,int a2, int b1, int b2)
{
    //初始化
	queue<int> q;
	q.push(a1);
	q.push(a2);
	while(!q.empty())
	{
		int m=q.front(); q.pop();
		int n=q.front(); q.pop();
		if(m == b1 && n == b2) 
		    break;
		for(int i=0;i<8;i++)
		{
			int mm=m + dir[i][0];
			int nn=n + dir[i][1];
			if(mm < 1 || mm > 1000 || nn < 1 || nn > 1000) { //越界
		    	continue;
			}
			if(!moves[mm][nn]) //如果这个位置已经有值了,说明走回头路了
			{
				moves[mm][nn]=moves[m][n]+1; //移动一次
				q.push(mm);
				q.push(nn);
			}
		}
	}
}
int main()
{
    int n, a1, a2, b1, b2;
    cin >> n;
    while (n--) {
        cin >> a1 >> a2 >> b1 >> b2;
        memset(moves,0,sizeof(moves)); //此函数的意思是将数组moves里面的元素,都改为0,相当于每一次都需要重置moves数组一次。
		bfs(a1, a2, b1, b2);
		cout << moves[b1][b2] << endl;
	}
	return 0;
}

但显然广搜的时间复杂度很高,进行了很多无用的查询。

A*算法 

Astar算法是一种广搜的改良版算法,也可以说是dijkstra的改良版算法。其实我们在进行搜索最短路的时候,如果边的权值都是1,那么我们一般使用广搜来进行,代码简洁时间效率和dijkstra相同,但是,如果是带权图,那么优先考虑dijkstra算法。

而Astar算法的关键就在于启发式函数,也就是影响广搜或者dijkstra从队列里取出元素的顺序。

首先我们知道在BFS中,我们搜索起点到终点的最短距离,是一层一层的去遍历的。 

但如果使用Astar算法话,其搜索过程其实是这样的:

换句话说BF是没有目的性的一圈一圈去搜索,而Astar算法是有方向性的去搜索。因此能够节省很多不必要的步骤。

因此我们现在所需要知道的关键就是,Astar算法,是如何确定出方向的。关键就在于启发函数。由于我们每次递归,都是从队列中选出两个点进行搜索,因此启发函数的作用就是影响队列里面的顺序!让朝着目标方向的点先出队列进行搜索。

因此启发函数其实就是计算遍历点到终点距离的一个公式。为了影响节点在队列中的顺序,我们可以给每个节点一个权值F,F = G + H。G:起点达到目前遍历节点的距离;H:目前遍历的节点到达终点的距离,F就表示起点到目标节点的距离,显然两点相连直线最短,这样就保证了,朝着相连直线的方向前进。

本题的图是无权网格状,在计算两点距离通常有如下三种计算方式:

  1. 曼哈顿距离,计算方式: d = abs(x1-x2)+abs(y1-y2)
  2. 欧氏距离(欧拉距离) ,计算方式:d = sqrt( (x1-x2)^2 + (y1-y2)^2 )
  3. 切比雪夫距离,计算方式:d = max(abs(x1 - x2), abs(y1 - y2))

x1, x2 为起点坐标,y1, y2 为终点坐标 ,abs 为求绝对值,sqrt 为求开根号。采用不同的距离公式,也会使得Astar算法的结果不同,本题我们采用欧拉距离公式,更大程度体现点与点之间的距离。

接着解题思路就是,计算出每个点的F,然后按照F的大小,来选取出队列中的节点,这个过程可以使用优先级队列来帮忙进行排序,每次出队列,就是F最小的节点。

代码:

#include<iostream>
#include<queue>
#include<string.h>
using namespace std;

int moves[1001][1001]; //棋盘大小
int dir[8][2]={-2,-1,-2,1,-1,2,1,2,2,1,2,-1,1,-2,-1,-2}; //八个方向
int b1, b2; //记录终点,设为全局变量方便计算欧拉距离使用


struct Knight{ //创建一个结构体其实,来存储坐标信息,和权值
    int x,y;
    int g,h,f;
    bool operator < (const Knight & k) const{  // 重载运算符, 从小到大排序
        return k.f < f;
    }
};

priority_queue<Knight> que; //优先级队列

int Heuristic(const Knight& k) { // 欧拉距离
    return (k.x - b1) * (k.x - b1) + (k.y - b2) * (k.y - b2); // 统一不开根号,这样可以提高精度
}
void astar(const Knight& k)
{
    Knight cur, next; 
	que.push(k); 
	while(!que.empty())
	{
		cur = que.top(); 
		que.pop();
		if(cur.x == b1 && cur.y == b2) { //找到了目标终点
		    break;
		}
		for(int i = 0; i < 8; i++) //遍历八个方向
		{
			next.x = cur.x + dir[i][0];
			next.y = cur.y + dir[i][1];
			if(next.x < 1 || next.x > 1000 || next.y < 1 || next.y > 1000) { //越界
			    continue;
			}
			if(!moves[next.x][next.y]) //如果这个位置已经有值了,说明走回头路了
			{
				moves[next.x][next.y] = moves[cur.x][cur.y] + 1;
                // 计算F
				next.g = cur.g + 5; // 统一不开根号,提高精度,骑士属于马走日,每次距离都会是5
                next.h = Heuristic(next);
                next.f = next.g + next.h;
                que.push(next); //优先级队列中,会自动把f小的放前面
			}
		}
	}
}

int main()
{
    int n, a1, a2;
    cin >> n;
    while (n--) {
        cin >> a1 >> a2 >> b1 >> b2;
        memset(moves,0,sizeof(moves)); //每一次将棋盘重置
        Knight start;
        start.x = a1;
        start.y = a2;
        start.g = 0;
        start.h = Heuristic(start);
        start.f = start.g + start.h;
		astar(start); //算法开始
        while(!que.empty()) que.pop(); // 队列清空,进入下一次循环
		cout << moves[b1][b2] << endl;
	}
	return 0;
}

复杂度分析 

Astar算法的复杂度,主要取决于启发式函数怎么写。最坏情况下,A * 退化成广搜,算法的时间复杂度是 O(n * 2),n 为节点数量。最佳情况,是从起点直接到终点,时间复杂度为 O(dlogd),d 为起点到终点的深度,这个时间复杂度也是堆排序的时间复杂度,也就是使用优先级队列的时间复杂度。实际上 A * 的时间复杂度是介于最优和最坏情况之间, 可以非常粗略的认为 A * 算法的时间复杂度是 O(nlogn) ,n 为节点数量。

A * 算法的空间复杂度 O(b ^ d) ,d 为起点到终点的深度,b是图中节点间的连接数量,本题因为是无权网格图,所以节点间连接数量为 4,四个方向。

A*算法的缺点

显然我们在运行A*算法的时候,向队列中添加了很多节点,但是实际取出来的仅仅是靠启发函数判断的距离中终点最近的接待你。因此可以说相较于BFS广度搜索算法,我们只是取出了最近的节点而已。这样就会导致大量不需要访问的节点都在队列里,会造成空间的过度消耗。

IDA * 算法对这一空间增长问题进行了优化,关于 IDA * 算法,还需要后续进行学习。

另外如果是给出多个可能的目标,然后在这多个目标中选择最近的目标,这样的场景A *是解决不了的。


最短路算法总结篇 

最短路径算法可总结为四种算法:Dijkstra、Bellman_ford、SPFA 和 Floyd。(A*算作是广度搜索算法的优化)总计又包含:

  • dijkstra朴素版
  • dijkstra堆优化版
  • Bellman_ford
  • Bellman_ford 队列优化算法(又名SPFA)
  • bellman_ford 算法判断负权回路
  • bellman_ford之单源有限最短路
  • Floyd 算法精讲
  • 启发式搜索:A * 算法

每个算法,都有各自的应用场景,用一个表格表示为:


图论总结

图论正式完结了!!!图论包含了:

深搜和广搜

深搜与广搜是图论里基本的搜索方法,大家需要掌握三点:

  • 搜索方式:深搜是可一个方向搜,不到黄河不回头。 广搜是围绕这起点一圈一圈的去搜。
  • 代码模板:需要熟练掌握深搜和广搜的基本写法。
  • 应用场景:图论题目基本上可以即用深搜也可用广搜,无疑是用哪个方便而已

并查集

并查集重点是要理解以下几个部分:

  • 为什么要用并查集,怎么不用个二维数据,或者set、map之类的。(时间复杂度高,不方便)
  • 并查集能解决那些问题,哪些场景会用到并查集(两个节点是否在一个集合,将两个节点加入到一个集合)
  • 并查集原理以及代码实现
  • 并查集写法的常见误区
  • 带大家去模拟一遍并查集的过程
  • 路径压缩的过程
  • 时间复杂度分析

最小生成树 

最小生成树算法,有prim 和 kruskal。

prim 算法是维护节点的集合,而 Kruskal 是维护边的集合。

在 稀疏图中,用Kruskal更优。 在稠密图中,用prim算法更优。

关于 prim算法,我自创了三部曲,来帮助大家理解:

  1. 第一步,选距离生成树最近节点
  2. 第二步,最近节点加入生成树
  3. 第三步,更新非生成树节点到生成树的距离(即更新minDist数组)

minDist数组 是prim算法的灵魂,它帮助 prim算法完成最重要的一步,就是如何找到距离最小生成树最近的点

kruscal的主要思路:

  • 边的权值排序,因为要优先选最小的边加入到生成树里
  • 遍历排序后的边:如果边首尾的两个节点在同一个集合,说明如果连上这条边图中会出现环;如果边首尾的两个节点不在同一个集合,加入到最小生成树,并把两个节点加入同一个集合

而判断节点是否在一个集合以及将两个节点放入同一个集合,正是并查集的擅长所在。所以 Kruskal 是需要用到并查集的。

拓扑排序 

拓扑排序是在图上的一种排序。给出一个有向图,把这个有向图转成线性的排序就叫拓扑排序。同样,拓扑排序也可以检测这个有向图是否有环,即存在循环依赖的情况。

只要记住如下两步拓扑排序的过程,代码就容易写了:

  1. 找到入度为0 的节点,加入结果集
  2. 将该节点从图中移除

最短路算法 

最短路算法是图论中,比较复杂的算法,而且不同的最短路算法都有不同的应用场景。

可总结为四种算法:Dijkstra、Bellman_ford、SPFA 和 Floyd。(A*算作是广度搜索算法的优化)总计又包含:

  • dijkstra朴素版
  • dijkstra堆优化版
  • Bellman_ford
  • Bellman_ford 队列优化算法(又名SPFA)
  • bellman_ford 算法判断负权回路
  • bellman_ford之单源有限最短路
  • Floyd 算法精讲
  • 启发式搜索:A * 算法

总结 

代码随想录60天的训练营!!!完结撒花,谢谢卡哥,谢谢代码随想录🎇🎇,后续还会有二刷,三刷!!!。

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

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

相关文章

log4j2: CVE-2021-44228[RCE]

漏洞概述 CVE-2021-44228为Apache Log4j2漏洞&#xff0c;被称为"Log4Shell"。攻击者将恶意代码与服务器进行交互&#xff0c;使服务器日志组件将其记录并执行&#xff0c;从而造就RCE远程代码执行漏洞。 漏洞原理 日志记录机制&#xff1a;Log4j2是一个日志记录工…

【ML】自监督学习 self-supervised Learning

【ML】 自监督学习 1. 自监督学习 bert 为例子1.1 BERT 的特点&#xff1a;1.2 BERT 的模型结构&#xff1a;1.3 训练 BERT 的步骤&#xff1a; 2. how to use BERT![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f8cccb378f844923a057043fadb60758.png)2. multi-lin…

DL00765-光伏故障检测高分辨率无人机热红外图像细粒度含数据集4000+张

光伏发电作为清洁能源的重要组成部分&#xff0c;近年来得到了广泛应用。然而&#xff0c;随着光伏电站规模的扩大&#xff0c;光伏组件在运行过程中可能会出现各种故障&#xff0c;如热斑、遮挡、接线盒故障等。这些故障不仅会影响光伏电站的发电效率&#xff0c;还可能导致更…

【日常开发】 java返回ECharts数据结构封装

java返回ECharts数据结构封装 一、前端页面示例图如下&#xff1a; 二、准备测试数据&#xff1a; 三、后端 格式封装代码&#xff1a; 四、最终结果&#xff1a; &#x1f388;边走、边悟&#x1f388;迟早会好 一、前端页面示例图如下&#xff1a; 二、准备测试数据&am…

4.11.seq2seq 序列到序列学习

序列到序列学习(seq2seq) ​ 使用两个循环神经网络的编码器和解码器&#xff0c;应用于序列到薛烈类的学习任务。 ​ ​ 在图中&#xff0c;特定的"<eos>"表示序列结束词元。一旦输出序列生成此词元&#xff0c;模型就会停止预测。在循环神经网络解码器的初…

Go语言中gin+gorm开发前端端分离博客时遇到的问题,gorm执行查询时如何选中特定字段?

代码获取 本篇文章的代码放在了Github上&#xff0c;可以免费获取。 https://github.com/zhangdapeng520/zdpgo_gin_examples 概述 在查询用户信息的时候&#xff0c;由于密码这个字段比较敏感&#xff0c;需要进行处理&#xff0c;不要返回给前端。 我一开始的解决方案是直…

统计学:条件概率模型

照片由Edge2Edge Media在Unsplash上拍摄 一、介绍 在概率的许多应用中&#xff0c;不可能直接观察实验的结果&#xff1b;而是观察与结果相关的事件。因此&#xff0c;条件概率模型对于考虑和利用从观察到的事件中获得的信息至关重要。此外&#xff0c;条件概率模型与贝叶斯定理…

【vue3】【elementPlus】【黑暗模式】

从创建vue3项目到引入elementPlus组件并设置黑暗模式 1.创建vue3项目&#xff1a; npm init vuelatest1.1 根据需求定制项目插件&#xff1a; 2.引入elementPlus组件&#xff1a; npm install element-plus --save2.1 如图注册全局elementPlus组件&#xff1a; ------------…

充电不再难,高质量充电体系‘智’领绿色出行新时代

充电不再难&#xff0c;高质量充电体系‘智’领绿色出行新时代 国家发展改革委新闻发言人近日在新闻发布会上郑重声明&#xff0c;将持续强化统筹协调&#xff0c;协同各相关部门加速构建高质量充电基础设施体系&#xff0c;以更有效地满足人民群众对绿色出行的需求。 新能源汽…

C语言:文件处理

文件处理 一、文件的类型&#xff08;一&#xff09;文本文件和二进制文件 &#xff08;二&#xff09;程序文件和数据文件数据文件按照二进制储存 二、文件的打开和关闭&#xff08;一&#xff09;文件指针&#xff08;二&#xff09;文件的打开和关闭1、fopen2、fclose &…

webshell管理工具-中国蚁剑

中国蚁剑 版本说明&#xff1a;中国蚁剑 下载地址&#xff1a;GitHub - AntSwordProject/AntSword-Loader: AntSword 加载器AntSword 加载器. Contribute to AntSwordProject/AntSword-Loader development by creating an account on GitHub.https://github.com/AntSwordProj…

数值分析【2】

目录 第三章 求解三角方程组​编辑 高斯消元​编辑 乘除次数&#xff1a;系数阵k^2,每行系数计算1&#xff0c;右边那列1 乘除总次数&#xff1a;​编辑 平方和 公式 列主元消去法 ​编辑 目的&#xff1a;舍入误差不扩散​编辑 直接LU分解​编辑 改进平方…

C#开发常见面试题三(浅复制和深复制的区别)

C#开发常见面试题三(浅复制和深复制的区别) 一.浅复制和深复制定义 &#xff08;1&#xff09;浅复制&#xff1a;复制一个对象的时候&#xff0c;仅仅复制原始对象中所有的非静态类型成员和所有的引用类型成员的引用。&#xff08;新对象和原对象将共享所有引用类型成员的实…

django如何更新数据库字段并与数据库保持同步?

关键步骤&#xff1a; 第一步&#xff1a; 执行&#xff1a;python manage.py makemigrations 你的项目名称第二步&#xff1a;它会提示你选1还是2&#xff0c;这里因为添加字段&#xff0c;所以选1第三步&#xff1a;出现>>>这个&#xff0c;直接输入这个第四步&am…

Win11+docker+vscode配置anomalib并训练自己的数据(3)

在前两篇博文中,我使用Win11+docker配置了anomalib,并成功的调用了GPU运行了示例程序。这次我准备使用anomalib训练我自己的数据集。 数据集是我在工作中收集到的火腿肠缺陷数据,与MVTec等数据不同,我的火腿肠数据来源于多台设备和多个品种,因此,它们表面的纹理与颜色差异…

C语言 | Leetcode C语言题解之第329题矩阵中的最长递增路径

题目&#xff1a; 题解&#xff1a; const int dirs[4][2] {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; int rows, columns;typedef struct point {int x, y; } point;int longestIncreasingPath(int** matrix, int matrixSize, int* matrixColSize) {if (matrixSize 0 || matrixC…

基于双PI+EKF扩展卡尔曼滤波的PMSM速度控制simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 PMSM数学模型 4.2 双PI控制器设计 4.3 扩展卡尔曼滤波器(EKF) 4.4 控制系统实现 5.完整工程文件 1.课题概述 基于双PIEKF扩展卡尔曼滤波的PMSM速度控制simulink建模与仿真。对比基于双PI的扩展卡…

【C/C++笔记】:易错难点3 (二叉树)

选择题 &#x1f308;eg1 一棵有15个节点的完全二叉树和一棵同样有15个节点的普通二叉树&#xff0c;叶子节点的个数最多会差多少个&#xff08;&#xff09;&#xff1f; 正确答案&#xff1a; C A. 3 B. 5 C. 7 D. 9 解析&#xff1a;普通二叉树的叶子节…

Java刷题:轮转数组

目录 题目 解题思路 完整代码 题目 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解题思路 主要的解题思路是&#xff0c;先把整个数组翻转过来&a…

如何解决.NET8 类库Debug时,Debug文件夹中不包含Packages中引入的文件

最近在开发中使用了.NET8 Razor类库项目&#xff0c;但是惊讶的发现Debug时&#xff0c;Debug文件夹中不包含Packages中引入的文件&#xff0c;本以为是非常小的问题&#xff0c;但是被困住了竟然足足4个小时。 其实它也本就是个非常非常小的问题…… 只需引入<CopyLocalL…