首页 > 编程语言 >Floyd算法——AcWing 343. 排序

Floyd算法——AcWing 343. 排序

时间:2024-07-14 15:25:44浏览次数:14  
标签:dist int 路径 算法 Floyd 343 顶点 AcWing

目录

Floyd算法

定义

运用情况

注意事项

解题思路

基本步骤

AcWing 343. 排序 

题目描述

运行代码

代码思路

改进思路

Floyd算法

定义

Floyd算法,全称Floyd-Warshall算法,是一种用于解决图中所有顶点对之间的最短路径问题的动态规划算法。它适用于带权有向图,且可以处理负权重边(但不能处理含有负权重循环的图),并能够检测出图中是否存在负权重循环。

运用情况

  1. 计算所有顶点对之间的最短路径:在诸如社交网络分析、交通网络规划、通信网络设计等领域,需要计算任意两点间的最短距离时,Floyd算法是一个很好的选择。
  2. 检测负权重循环:在某些应用场景下,需要确保图中不存在负权重循环,因为这可能表示系统中的某种异常或错误状态。

注意事项

  • 内存消耗:Floyd算法的空间复杂度为O(n^2),其中n是图中顶点的数量。对于大规模图,这可能成为一个问题。
  • 时间复杂度:Floyd算法的时间复杂度为O(n^3),在顶点数量很大的情况下,算法可能会变得非常慢。
  • 负权重循环:如果图中存在负权重循环,Floyd算法会陷入无限循环,因为从一个节点出发,通过该循环可以无限次减少路径长度。在实际应用中,需要先检测并处理这类情况。
  • 算法可以检测负权重循环:如果在算法执行过程中发现某个顶点到自身的最短路径小于0,即D[i][i] < 0,那么图中存在至少一个负权重循环,此时算法无法给出正确的最短路径结果。
  • 对于非常大的图,算法的高时间复杂度和空间复杂度可能成为瓶颈,这时可能需要考虑更高效的算法或者使用更专业的数据结构和优化技术。

解题思路

Floyd算法的核心思想是动态规划,其基本步骤如下:

  1. 初始化:将距离矩阵D设置为图的邻接矩阵,即D[i][j] = weight(i, j);对于i != j,如果(i, j)不连通,则D[i][j] = ∞;D[i][i] = 0。
  2. 动态规划:对于k = 1 到 n,更新D,使得D[i][j] = min(D[i][j], D[i][k] + D[k][j]),即检查是否可以通过中间节点k来缩短i到j的距离。
  3. 结果:最终的D矩阵包含了所有顶点对之间的最短路径长度。如果存在某个D[i][j] < 0且i != j,在更新过程中出现了D[i][i] < 0的情况,说明图中存在负权重循环。

Floyd算法的实现通常使用三重循环,外层循环遍历所有的中间顶点k,内两层循环遍历所有顶点对(i, j),检查是否存在更短路径。

基本步骤

假设我们有一个带权图G,其中包含n个顶点,我们可以用一个二维数组dist[][]来存储每对顶点之间的最短路径长度。初始时,dist[i][j]被设定为图中直接相连的边的权重,如果i和j之间没有直接相连的边,则dist[i][j]被设定为无穷大(表示不可达)。

  1. 初始化:创建一个n×n的矩阵D,其中D[i][j]初始化为图中从i到j的直接边的权重,如果i和j之间没有直接边,则设为无穷大。对角线元素D[i][i] = 0。

  2. 动态规划:对于每个顶点k(作为中间顶点),更新每对顶点i和j之间的最短路径,以k为中间点可能获得更短路径。更新公式为:D[i][j] = min(D[i][j], D[i][k] + D[k][j])。这意味着,如果通过k作为中间顶点,从i到j的路径变得更短了,就更新D[i][j]。

  3. 结果输出:经过n轮迭代后,矩阵D中的每个元素D[i][j]即为从i到j的最短路径长度。

AcWing 343. 排序 

题目描述

343. 排序 - AcWing题库

运行代码

#include <algorithm>
#include <bits/stdc++.h>
#include <iostream>
using namespace std;

#define PII pair<int, int>
#define fi first
#define se second
#define endl '\n'
map<int, int> mp;

const int N = 210, mod = 1e9 + 7;
int T, n, m, k;
int a[N], dist[N][N];
PII ans[N];

void floyd(int x) // 以 x 为中转点,更新其他点。
{
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            dist[i][j] = min(dist[i][j], dist[i][x] + dist[x][j]);
}

bool pd() // 判断是否所有点都已确定
{
    for (int i = 1; i <= n; i++) {
        int cnt = 0;
        for (int j = 1; j <= n; j++)
            if (dist[i][j] != 1e9)
                cnt++; // 当前点能到达的点数
        ans[i] = {cnt, i};
        for (int j = 1; j <= n; j++)
            if (i != j && dist[j][i] != 1e9)
                cnt++; // 能到达当前点的点数
        if (cnt != n)
            return 0;
    }
    sort(ans + 1, ans + n + 1);
    return 1;
}

int main() {
    while (cin >> n >> m && n) {
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (i != j)
                    dist[i][j] = 1e9;

        int flag = 0;
        for (int i = 1; i <= m; i++) {
            char a, t, b;
            cin >> a >> t >> b;
            int x = a - 'A' + 1, y = b - 'A' + 1; // 现在要加一条从 y 到 x 的边

            if (!flag && dist[x][y] != 1e9) // 发现已经从x能到y,出现矛盾
            {
                printf("Inconsistency found after %d relations.\n", i);
                flag = 1;
            }

            dist[y][x] = 1;
            floyd(x), floyd(y); // 分别以 x 和 y 为中转点更新其他点
            if (!flag && pd()) { // 发现所有点都已确定
                printf("Sorted sequence determined after %d relations: ", i);
                for (int i = 1; i <= n; i++)
                    cout << char(ans[i].se + 'A' - 1);
                printf(".\n");
                flag = 1;
            }
        }
        if (!flag)
            printf("Sorted sequence cannot be determined.\n"); // 无法确定
    }

    return 0;
}

代码思路

  1. 初始化: 使用一个dist二维数组初始化为无穷大,表示不等式间默认没有确定的顺序关系。
  2. 读取输入: 从标准输入读取关系,格式为“B > A”,表示B优于A。
  3. 关系处理:
    • 当读取到新的关系时,检查是否有矛盾(即之前已确定的关系与新关系冲突)。
    • 更新dist矩阵,使用Floyd算法更新所有不等式之间的最短路径,这里实际上是更新“优先级”或“排序”的关系。
  4. 检查排序确定性:
    • 检查是否所有不等式之间的关系都已经确定,即每个点都能到达其他所有点,且路径长度不是无穷大。
    • 如果在读取关系的过程中就发现了排序确定,或者读取完所有关系后仍然无法确定排序,输出相应信息。

改进思路

  • 效率提升: 当前的floyd调用在每次添加新关系后立即进行,这可能不是必要的。可以等到所有关系读取完毕后再进行一次Floyd算法,以减少不必要的计算。
  • 简化逻辑: 目前的代码在检测矛盾和确定排序完成的逻辑较为复杂。可以尝试简化逻辑,比如使用更直观的数据结构或算法步骤来检查这些条件。
  • 代码清晰性: 可以增加注释和代码结构的清晰度,使得代码更易于理解和维护。

标签:dist,int,路径,算法,Floyd,343,顶点,AcWing
From: https://blog.csdn.net/u014114223/article/details/140334239

相关文章

  • (4-5)Floyd-Warshall算法:高速公路路线查询系统
    4.5 高速公路路线查询系统本项目基于阿鲁巴岛的实际公路数据,实现了Floyd-Warshall算法来计算所有高速公路节点之间的最短路径。通过解析包含路线和节点地理位置信息的文本文件,程序构建了一个加权邻接矩阵,并利用哈佛赛因距离计算路径权重。最终,项目输出展示了阿鲁巴岛上各......
  • (4-3)Floyd-Warshall算法:Floyd-Warshall算法的应用案例
    4.3 Floyd-Warshall算法的应用案例Floyd-Warshall算法在许多实际应用中都有着广泛的应用,特别是在需要计算图中所有顶点对之间的最短路径时,它是一种非常有效的解决方案。4.3.1  自驾线路规划暑假来临,家庭A决定自驾旅行,计划去四个城市:A、B、C、D,每个城市之间的行车距离如......
  • Acwing 5729.闯关游戏 状压DP
    Acwing5729.闯关游戏状压DP题目链接题意:现在进行一个闯关游戏,一共有\(n\)个关卡,第\(i\)个关卡的分数为\(w_i\)。另外还有\(k\)个联动彩蛋。如果玩家通过第\(x\)个关卡后,紧接着通过了第\(y\)个关卡,就可以获得额外\(c\)分。现在你需要恰好通过\(m\)个不同关卡,顺......
  • 最小步数模型——AcWing 1107. 魔板
    最小步数模型定义最小步数模型通常是指在某种约束条件下,寻找从初始状态到目标状态所需的最少操作或移动次数的问题。这类问题广泛存在于算法、图论、动态规划、组合优化等领域。具体来说,它涉及确定一个序列或路径,使得按照特定规则执行一系列步骤后,能够从起始位置或状态转换到......
  • 【AcWing】843. n皇后问题
    剪纸就是判断当前方案一定不合法了就不往下搜了,把这个枝减掉,直接回溯。代码#include<iostream>usingnamespacestd;constintN=10;intn;charg[N][N];//棋盘boolcol[N],dg[N*2],udg[N*2];//分别代表列斜线反斜线有没有占用,对角线个数为2n-1,开2nvoiddfs(......
  • 【AcWing】842. 排列数字(DFS)
    DFS是树形结构,深度优先搜索。dfs可以算作递归。横线上填和前面不一样的数字。每一次向下探索都一条路走到黑,直到不能走再回溯。#include<iostream>usingnamespacestd;constintN=10;intn;intpath[N];//存放走过的路径boolst[N];//存放1~n哪个数用过了,全局b......
  • 贪心推公式——AcWing 125. 耍杂技的牛
    贪心推公式定义贪心算法是一种在每一步选择中都采取在当前状态下最优的选择,希望通过局部的最优选择来得到全局最优解的算法策略。运用情况问题具有最优子结构,即一个问题的最优解包含其子问题的最优解。可以通过局部最优决策逐步推导到全局最优。问题的选择策略相对明确且易......
  • AcWing算法基础课笔记——求组合数3
    求组合数Ⅲ20万组数据,1≤b≤a≤1......
  • [题解]AT_abc343_g [ABC343G] Compress Strings
    思路首先假设有两个串\(a,b\),如果\(b\)是\(a\)的子串,且\(a\neqb\)则不需要考虑\(b\);如果\(a=b\),则如需要保留一个\(a\)。做完上述操作后,显然最终的答案是由这些串按照一定顺序拼接起来,再删掉重叠部分。例如:abbcc与ccdde拼接为abbccccdde,发现cc是重复的,所以......
  • AcWing算法基础课笔记——高斯消元
    高斯消元用来求解方程组a11x1+......