首页 > 编程语言 >搜索与图论2.2-Floyd算法

搜索与图论2.2-Floyd算法

时间:2023-10-15 19:37:18浏览次数:35  
标签:图论 int 路径 算法 Floyd 图中 顶点 2.2

一、简述

\(Floyd\) 算法是一种可以快速求解图上所有顶点之间最短路径的算法。

\(Bellman-Ford\) 和 \(Dijkstra\) 算法求解的都是从一个起始点开始的最短路。如果想要求解图中所有顶点之间的最短路,就需要枚举每个点做为起点,这样十分低效。\(Floyd\) 算法(也称 \(Floyd-Warshall\) 算法)处理用邻接矩阵存储的有向图(无向图的一条边可以看做有向图的两条边)十分方便。

二、Floyd算法

memset(f, 127, sizeof f);
f[0][i][j] = a[i][j];

for (int k = 1; k <= n; k++)
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			f[k][i][j] = min(f[k - 1][i][j], f[k - 1][i][k] + f[k - 1][k][j]);
  • \(f[k][i][j]\) 表示从 \(i\) 到 \(j\) 并且可以经过 \(1\) 至 \(k\) 的最短路径,\(f[0][i][j]\) 表示从 \(i\) 到 \(j\) 并且不经过任何中间点的最短路径。
  • \(a[i][j]\) 表示从 \(i\) 到 \(j\) 的边的长度,\(a[i][i]=0\)。

\(Floyd\) 算法是动态规划的思想。在转移方程中,从 \(i\) 到 \(j\) 的最短路径可以经过顶点 \(k\),也可以不经过顶点 \(k\),经过顶点 \(k\),则 \(k\) 将路径分为两段,前后两段最多只能经过 \(1\) 至 \(k-1\),不经过顶点 \(k\),则最多经过 \(1\) 至 \(k-1\)。

那么上述代码可以空间优化吗?答案是肯定的,优化后的代码如下

memset(f, 127, sizeof f);
f[i][j] = a[i][j];

for (int k = 1; k <= n; k++)
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (f[i][k] < 1 << 30 && f[k][j] < 1 << 30) // 注意int类型数据范围
				f[i][j] = min(f[i][j], f[i][k] + f[k][j]);

优化后,验证一下正确性,在加入顶点 \(k\) 之前,\(f[i][j]\) 就相当于 \(f[k-1][i][j]\),但是 \(f[i][k]\) 以及 \(f[k][j]\) 是有可能在 \(f[i][j]\) 之前被覆盖的,但是注意 \(f[k][i][j]\) 的含义为从 \(i\) 到 \(j\) 并且可以经过 \(1\) 至 \(k\) 的最短路径,那么 \(1\) 至 \(k\) 为中间点,则 \(f[k-1][i][k]=f[k][i][k]\) 并且 \(f[k-1][k][j]=f[k][k][j]\),因此可以使用 \(f[i][k] + f[k][j]\) 来替换。

关于路径的记录,可以使用 \(path\) 数组在距离更新时来记录,\(path[i][j]=k\),表示从 \(i\) 到 \(j\) 经过中间点 \(k\)(path[i][j]=-1$ 表示 \(i\) 和 \(j\) 直接相连),然后利用 \(k\) 将路径分为两部分,依次递归输出。

模板题AcWing854.Floyd求最短路

题目描述

给定一个 \(n\) 个点 \(m\) 条边的有向图,图中可能存在重边和自环,边权可能为负数。
再给定 \(k\) 个询问,每个询问包含两个整数 \(x\) 和 \(y\),表示查询从点 \(x\) 到点 \(y\) 的最短距离,如果路径不存在,则输出 impossible
数据保证图中不存在负权回路。

输入格式

第一行包含三个整数 \(n,m,k\)。
接下来 \(m\) 行,每行包含三个整数 \(x,y,z\),表示存在一条从点 \(x\) 到点 \(y\) 的有向边,边长为 \(z\)。
接下来 \(k\) 行,每行包含两个整数 \(x,y\),表示询问点 \(x\) 到点 \(y\) 的最短距离。

输出格式

共 \(k\) 行,每行输出一个整数,表示询问的结果,若询问两点间不存在路径,则输出 impossible

数据范围

\(1≤n≤200\),
\(1≤k≤n^2\),
\(1≤m≤20000\),
图中涉及边长绝对值均不超过 \(10000\)。

输入样例
3 3 2
1 2 1
2 3 2
1 3 1
2 1
1 3
输出样例
impossible
1
C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 210, INF = 1e9;

int n, m, q;
int dist[N][N];

void floyd() {
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}

int main() {
    cin >> n >> m >> q;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            if (i == j) 
                dist[i][j] = 0;
            else 
                dist[i][j] = INF;
        }
    while (m--) {
        int x, y, z;
        cin >> x >> y >> z;
        dist[x][y] = min(dist[x][y], z);
    }
    floyd();
    while (q--) {
        int x, y;
        cin >> x >> y;
        if (dist[x][y] > INF / 2) 
            puts("impossible");
        else 
            cout << dist[x][y] << endl;
    }
    return 0;
}

三、Floyd算法的应用

这里给出一个和 \(Floyd\) 算法思想相关的题目。

Daimayuan Online Judge.删点游戏

题目描述

给你一张 \(n\) 个顶点的有向简单图,顶点编号从 \(1\) 到 \(n\),我们要把所有顶点一个一个删完。小蜗每次会删掉图中的一个顶点和所有与它相连的边,小蜗想知道每删去一个顶点之后图中所有点对的距离之和。

输入格式

第一行一个整数 \(n\),表示顶点数。
接下来 \(n\) 行,每行 \(n\) 个整数,组成一个 \(n×n\) 的矩阵 \(A\) 表示这张图的邻接矩阵,矩阵第 \(i\) 行第 \(j\) 列表示 \(i\) 号顶点到 \(j\) 号顶点有一条边权为 \(A[i][j]\) 的边。
接下来一行,输入 \(n\) 个数 \(x_1,x_2,...,x_n\),代表删除顶点的顺序。

输出格式

输出一行 \(n\) 个数依次表示删除了第 \(0\) 个点(一个点都没删除)到第 \(n−1\) 个点(图中还剩下一个点)后,图中所有剩下的点对的距离之和。

数据范围

对于所有数据,保证 \(2≤n≤300,1≤A[i][j]≤10000,A[i][i]=0,1≤x_i≤n\)。

输入样例
2
0 5
4 0
1 2
输出样例
9 0
解题思路

根据题目描述,按照给定的顺序删除顶点,计算剩余各点之间的最短路的距离和。在 \(Floyd\) 算法中,在求解过程中是依次枚举中间点 \(k\),那么就相当于每次都增加一个顶点,因此此问题可以逆向为按照给点的顺序依次增加顶点,计算图中已有顶点之间的最短路的距离和。
在顶点的增加中,利用布尔数组来表示某一顶点是否在图中,在计算最短路距离和的时候需要考虑当前的顶点是否在图中。

C++代码
#include <bits/stdc++.h> 
using namespace std;
const int N = 310, M = 65;
typedef long long LL;

int n;
int x[N], dist[N][N];
bool b[N];
int a[N];

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			scanf("%d", &dist[i][j]);
	for (int i = 1; i <= n; i++)
		scanf("%d", &x[i]);
	for (int l = n; l; l--) {
		int k = x[l];
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
		b[k] = true;
		int ans = 0;
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				if (b[i] && b[j])
					ans += dist[i][j];
		a[l] = ans;
	}
	for (int i = 1; i <= n; i++)
		printf("%d ", a[i]);
    return 0;
}

标签:图论,int,路径,算法,Floyd,图中,顶点,2.2
From: https://www.cnblogs.com/Cocoicobird/p/17765950.html

相关文章

  • 图论总结
    图论树和图的存储`树是特殊的图,无环的联通图图分为有向图和无向图,无向图是一种特殊的有向图`邻接矩阵存稠密图,空间复杂度\(O(n^2)\)g[u][v]=w;邻接表voidinit(){ for(inti=0;i<N;i++) h[i]=-1;}voidadd(inta,intb){//在链表头插......
  • Codeforces Round 903 (Div. 3) F. Minimum Maximum Distance(图论)
    CodeforcesRound903(Div.3)F.MinimumMaximumDistance思路对标记点更新fg,从0开始进行bfs,更新d1为所有点到0的距离获得到0最远的标记点L,从L开始bfs,更新d2为所有点到L的距离获得距离L最远的标记点R,从R开始bfs,更新d3为所有点到R的距离遍历所有点,这个点与标记点的最大距......
  • 【2023潇湘夜雨】WIN11_Pro_23H2.22631.2428软件选装纯净版10.12
    【系统简介】=============================================================1.本次更新母盘来自WIN11_Pro_23H2.22631.2428。2.增加部分优化方案,手工精简部分较多。3.OS版本号为22631.2428。精简系统只是为部分用户安装,个别要求高的去MSDN下。4.集成《DrvCeo-2.13.0.8》网卡版、......
  • 图论
    \(DFS\)\(DFS\)全称是\(Depth\First\Search\),中文名是深度优先搜索,是一种用于遍历或搜索树或图的算法。所谓深度优先,就是说每次都尝试向更深的节点走。\(DFS\)最显著的特征在于其递归调用自身。同时与\(BFS\)类似,\(DFS\)会对其访问过的点打上访问标记,在遍历图时跳过已......
  • Floyd 警示后人
    遍历的中转点一定要在最外层遍历!!!不然就会错误的代码↓ for(inti=1;i<=n;++i){ for(intj=1;j<=n;++j){ if(i==j)continue; for(intk=1;k<=n;++k){ if(i==k||j==k)continue; if(mp[i][k]+mp[k][j]<mp[i][j]) mp[i][j]=mp[i][k]+mp[k][j]; } } }......
  • 弗洛伊德(Floyd's)算法—解决最短路径经典算法
    弗洛伊德算法(Floyd'salgorithm)是一种用于解决图中最短路径问题的经典算法。由美国计算机科学家罗伯特·弗洛伊德于1962年提出,该算法通过动态规划的思想,在图中寻找任意两个节点之间的最短路径,具有广泛的应用。本文将详细介绍弗洛伊德算法的原理、实现细节以及应用案例。四、复杂度......
  • 模拟集成电路设计系列博客——2.2.3 折叠Cascode放大器的摆率
    2.2.3折叠Cascode放大器的摆率两个二极管接法的晶体管\(Q_{12}\)和\(Q_{13}\)在正常工作时截止,对于放大器的工作几乎没有影响。但是他们能共有效的提升数倍摆率[Law,1983]。为了理解他们的功能,首先考虑没有这两个晶体管时的摆率限制。假定有一个很大的输入差分电压导致\(Q_1\)......
  • 图论——树上问题 学习笔记
    图论——树上问题学习笔记目录树的直径树的重心树的中心经典问题1:最小化最大距离树的直径定义树上任意两节点之间最长的简单路径即为树的直径。显然,一棵树可以有多条直径,他们的长度相等。性质若树上所有边边权均为正,则树的所有直径有交,且中点重合;有树的直径\((p,q......
  • 12.2 实现键盘模拟按键
    本节将向读者介绍如何使用键盘鼠标操控模拟技术,键盘鼠标操控模拟技术是一种非常实用的技术,可以自动化执行一些重复性的任务,提高工作效率,在Windows系统下,通过使用各种键盘鼠标控制函数实现动态捕捉和模拟特定功能的操作。键盘鼠标的模拟是实现自动化的必备流程,通常我们可以使用key......
  • 图论
    图论这……感觉是知识点多,算法多,但用的频率不一定高,容易忘记,这里就整点板子防老年痴呆欧拉路径即一笔画问题,定义为:图中经过所有边恰好一次的路径叫欧拉路径。如果此路径的起点和终点相同,则称其为一条欧拉回路。注意图必须连通,可用并查集或dfs判断关于判断欧拉路径是否存在:以......