图的最短路径算法Floyed

news/2024/10/4 6:16:32 标签: 算法, c++, , 最短路径, floyed

带权

如下所示,我们把边带有权值的称为带权。边的权值可以理解为两点之间的距离。一张中任意两点间会有不同的路径相连。最短路径就是指连接两点的这些路径中最短的一条。
在这里插入<a class=图片描述" />
国庆期间有一个人计划旅行,地如下所示,这个人希望在出发前知道任意两个城市之间的最短路径
在这里插入<a class=图片描述" />
如何求解任意两点间最短路径呢?
我们很容易想到,通过深度或者广度优先搜索可以求出两点之间的最短路径。有没有别的办法?
下面来讲解floyed算法

floyed_8">floyed算法

思维:如果要让任意两点之间(假设是a到b)的路程变短,只能引入第三个点(假设为k),并通过这个点k进行中转即a->k->b,才可能缩短原来从顶点a到顶点b的路程。有时候可能还不只一个中转点,而是经过两个点或者更多的点进行中转会更短,即a->k1->k2->b或者a->k1->k2->…>b。比如上中的4号城市到3号城市的路程原本是a[4][3]=12, 如果通过1号城市中转4>1>3, 路程将缩短为11(e[4][1]+e[1][3]=5+6=11)。如果同时通过1号和2号两个城市中转的话,从4号城市到3号城市的路程会进一步缩短为10(e[4][1]+e[1][2]+e[2][3]=5+2+3=10)。通过以上分析,我们发现每个顶点都有可能 使得另外两个顶点之间的路程变短。下面我们来模拟该过程:

我们首先将这个存储起来,我们使用二维数组

比如1号城市到3号城市距离为6即e[1][3]=6,假如2无法到达4我们就表示为e[2][4]=∞,我们再设当前1号城市到1号城市距离为0,e[1][1]=0。二维数组如下:
在这里插入<a class=图片描述" />
假设现在只允许1号顶点中转,求任意两点之间(i到j)的最短路径
现在只需判断e[i][1]+e[1][j]是否比e[i][j]小,代码如下:

#include<iostream>
using namespace std;
int main()
{
	int e[10][10];
	int n,i,j;
	//经过1号顶点中转
	for (i = 1; i <= n; i++)
	{
		for (j = 1; j <= n; j++)
		{
			if (e[i][j] > e[i][1] + e[1][j])
			{
				e[i][j] = e[i][1] + e[1][j];
			}
		}
	}
}

在只经过1号中转的情况下任意两点之间的最短路径更新为:
在这里插入<a class=图片描述" />
接下来,求在只允许经过1和2号两个顶点的情况下任意两点之间的最短路径。怎么求呢?我们需要在只允许经过1号顶点时任意两点的最短路径的结果下,再判断如果经过2号顶点是否可以使得i号顶点到j号顶点之间的路程变得更短,即判断e[i][2]+e[2][]是否比e[i]i]要小,代码如下:

#include<iostream>
using namespace std;
int main()
{
	int e[10][10];
	int n,i,j;
	//经过1号顶点中转
	for (i = 1; i <= n; i++)
	{
		for (j = 1; j <= n; j++)
		{
			if (e[i][j] > e[i][1] + e[1][j])
			{
				e[i][j] = e[i][1] + e[1][j];
			}
		}
	}
	//经过2号顶点中转
	for (i = 1; i <= n; i++)
	{
		for (j = 1; j <= n; j++)
		{
			if (e[i][j] > e[i][2] + e[2][j])
			{
				e[i][j] = e[i][2] + e[2][j];
			}
		}
	}
}

在只经过1号和2号的中转的情况下,任意两点之间的最短路径更新为:
在这里插入<a class=图片描述" />
我们可以将以上情况写成三个for循环代码如下:

#include<iostream>
using namespace std;
int main()
{
	int e[10][10];
	int n,i,j,k;	
	for (k = 1; k <= n; k++)
	{
		for (i = 1; i <= n; i++)
		{
			for (j = 1; j <= n; j++)
			{
				if (e[i][j] > e[i][k] + e[k][j])
				{
					e[i][j] = e[i][k] + e[k][j];
				}
			}
		}
	}

}

注意:中间的点的变量k必须放在最外面一层循环。

Floyed算法总结:

Floyed算法可以算出任意两点的最短路径,可以处理带有负权边的,但不能处理带有“负环”的
负环就是累加起来为一个负数
在这里插入<a class=图片描述" />
时间复杂度:O(n^3)

最短路径问题

【问题描述】

平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离。现在的任务是找出从一点到另一点之间的最短路径

【输入格式】

输入文件为short.in,共n+m+3行,其中:
第一行为整数n。
第2行到第n+1行(共n行),每行两个整数x和y,描述了一个点的坐标。
第n+2行为一个整数m,表示中连线的个数。
此后的m行,每行描述一条连线,由两个整数i和j组成,表示第i个点和第j个点之间有连线。最后一行:两个整数s和t,分别表示源点和目标点。

【输出格式】

输出文件为short.out.仅一行 一个实数(保留两位小数),表示从s到t的最短路径长度。

输入样例

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

输出样例

3.41

在这里插入<a class=图片描述" />

代码如下:

#include<iostream>  // 引入标准输入输出库
#include<cmath>     // 引入数学库,用于计算平方根
#include<cstring>   // 引入字符串处理库,用于数组的初始化
using namespace std;

int a[101][3];      // 存储每个节点的坐标,最多 101 个节点,每个节点有两个坐标 x 和 y
double f[101][101]; // 存储两点之间的距离,f[i][j] 表示第 i 点和第 j 点之间的距离
int n, i, j, k, x, y, m, s, e; // n 为节点数量,m 为边的数量,s 为起点,e 为终点,x 和 y 为节点编号

int main()
{
    cin >> n;  // 输入节点数量
    // 循环输入每个节点的坐标
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i][1] >> a[i][2];  // 输入第 i 个节点的 x 和 y 坐标
    }

    cin >> m;  // 输入边的数量
    memset(f, 0x7f, sizeof(f));  // 初始化 f 数组,将其设为一个非常大的值(表示无穷大),避免误判最短路径

    // 输入每条边,计算并存储两个节点之间的欧氏距离
    for (i = 1; i <= m; i++)
    {
        cin >> x >> y;  // 输入两个节点编号
        // 计算两个节点之间的距离,使用欧氏距离公式 sqrt((x1 - x2)^2 + (y1 - y2)^2)
        f[y][x] = f[x][y] = sqrt(pow(double(a[x][1] - a[y][1]), 2) + pow(double(a[x][2] - a[y][2]), 2));
    }

    cin >> s >> e;  // 输入起点 s 和终点 e

    // 使用 Floyd-Warshall 算法求所有点对之间的最短路径
    for (k = 1; k <= n; k++)  // k 为中间点
    {
        for (i = 1; i <= n; i++)  // i 为起点
        {
            for (j = 1; j <= n; j++)  // j 为终点
            {
                // 如果通过中间点 k 到达终点的距离更短,则更新 f[i][j]
                if ((i != j) && (i != k) && (j != k) && (f[i][k] + f[k][j] < f[i][j]))
                {
                    f[i][j] = f[i][k] + f[k][j];  // 更新最短路径
                }
            }
        }
    }

    // 输出起点 s 到终点 e 的最短距离,保留两位小数
    printf("%.2lf\n", f[s][e]);

    return 0;  // 程序结束
}

http://www.niftyadmin.cn/n/5689587.html

相关文章

会声会影导出视频mp4格式哪个最高清,会声会影输出格式哪个清晰

调高分辨率后&#xff0c;mp4视频还是不清晰。哪怕全部使用4K级素材&#xff0c;仍然剪不出理想中的高画质作品。不是你的操作有问题&#xff0c;而是剪辑软件没选对。Corel公司拥有全球顶尖的图像处理技术&#xff0c;该公司研发的会声会影视频剪辑软件&#xff0c;在过去的20…

(十八)、登陆 k8s 的 kubernetes-dashboard 更多可视化工具

文章目录 1、回顾 k8s 的安装2、确认 k8s 运行状态3、通过 token 登陆3.1、使用现有的用户登陆3.2、新加用户登陆 4、k8s 可视化工具 1、回顾 k8s 的安装 Mac 安装k8s 2、确认 k8s 运行状态 kubectl proxy kubectl cluster-info kubectl get pods -n kubernetes-dashboard3、…

场景题5-如何设计一个敏感词过滤系统

下图是一个完整的文本审核流程&#xff0c;包括名单匹配、敏感词匹配、AI 机器审核、人工审 核四个环节。待审核文本需要顺次通过名单匹配、敏感词匹配、AI 机器审核三个流程&#xff0c; 若结果为嫌疑则需要人工审核&#xff0c;否则将直接给出确定的结果。 敏感词匹配功能可以…

Stable Diffusion绘画 | 来训练属于自己的模型:秋叶训练器使用

花了不少时间搜索尝试&#xff0c;都没有找到解决上一篇文章遗留问题的解决方案&#xff0c;导致无法使用 cybertronfurnace 这个工具来完成炼丹&#xff0c;看不到炼丹效果。 但考虑到&#xff0c;以后还是要训练自己的模型&#xff0c; 于是决定放弃 cybertronfurnace&…

chatgpt学术科研prompt模板有哪些?chatgpt的学术prompt有哪些?学术gpt,学术科研

chatgpt学术科研prompt 模板有哪些&#xff1f;chatgpt的学术prompt有哪些&#xff1f;学术gpt&#xff0c;学术科研 这里整理一下chatgpt学术提问的一些prompt&#xff0c;供参考 更多技巧可以使用行学AI&#xff08;xingxue-ai.com&#xff09;&#xff0c;你的学术科研AI助…

Oracle中MONTHS_BETWEEN()函数详解

文章目录 前言一、MONTHS_BETWEEN()的语法二、主要用途三、测试用例总结 前言 在Oracle数据库中&#xff0c;MONTHS_BETWEEN()函数可以用来计算两个日期之间的月份差。它返回一个浮点数&#xff0c;表示两个日期之间的整月数。 一、MONTHS_BETWEEN()的语法 MONTHS_BETWEEN(dat…

Microsoft 更新 Copilot AI,未來將能使用語音並看到你瀏覽的網頁

不過受到 Recall 事件的影響&#xff0c;更新的推出將更緩慢謹慎。 Microsoft 也同步對其網頁版及行動版的 Copilot AI 進行大改版。這主要是為網頁版換上了一個較為簡單乾淨的介面&#xff0c;並增加了一些新的功能&#xff0c;像是 Copilot Voice 能讓你與 AI 助手進行對話式…

平衡BST:AVL树的实现与机制

目录 AVL树的简介 AVL节点的构建 AVL树体的构建 具体片段解析 旋转算法 AVL树的验证 AVL树的简介 AVL树是一种自平衡的二叉搜索树&#xff0c;它在19世纪60年代由Adelson-Velsky和Landis首次提出。在AVL树中&#xff0c;任何节点的两个子树的高度最大差别为1&#xff0c;这…