算法提高-图论-floyd算法及其扩展应用

这篇具有很好参考价值的文章主要介绍了算法提高-图论-floyd算法及其扩展应用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

floyd算法及其扩展应用

AcWing 1125. 牛的旅行

#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

typedef pair<double, double> PDD;
#define x first
#define y second

const int N = 155;
double INF = 1e20;
double d[N][N];
double maxd[N];
char g[N][N];
int n;
PDD q[N];//记录每个点的坐标

double get_dist(PDD a, PDD b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}
int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> q[i].x >> q[i].y;
    
    for (int i = 0; i < n; i ++ ) cin >> g[i];//题目给的是一个字符串
    
    for (int i = 0; i < n; i ++ )
    {
        for (int j = 0; j < n; j ++ )
        {
            if (i == j) d[i][j] = 0;
            else if (g[i][j] == '1') d[i][j] = get_dist(q[i], q[j]);
            else d[i][j] = INF;
        }
    }
    
    for (int k = 0; k < n; k ++ )
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < n; j ++ )
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
        
    double r1 = 0;        
    for (int i = 0; i < n; i ++ )
    {
        for (int j = 0; j < n; j ++ )
            if (d[i][j] < INF / 2)//说明ij两个牧区在同一个牧场
                maxd[i] = max(maxd[i], d[i][j]);
        
        r1 = max(r1, maxd[i]);
    }
    
    double r2 = INF;
    for (int i = 0; i < n; i ++ )
    {
        for (int j = 0; j < n; j ++ )
        {//和INF / 2比较的原因是为了避免double精度不够,这样更保险一些
            if (d[i][j] > INF / 2)//说明ij两个牧区不在同一个牧场,需要连一条线、
                //r2 = min(r2, maxd[i] + d[i][j] + maxd[j]); 不能用d[i][j]获得i和j之间的距离,因为二者本来就不连通
                 r2 = min(r2, maxd[i] + maxd[j] + get_dist(q[i], q[j]));
        }
    }
    
    printf("%.6lf\n", max(r1, r2)); 
    return 0;
}

AcWing 343. 排序

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 26;

int g[N][N], d[N][N];
bool st[N];

int n, m;

void floyd()
{
    memcpy(d, g, sizeof d);
    
    for (int k = 0; k < n; k ++ )
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < n; j ++ )
                d[i][j] |= d[i][k] && d[k][j];
}

int check()
{
    for (int i = 0; i < n; i ++ )//自我冲突
        if (d[i][i] == 1) return 2;
    
    for (int i = 0; i < n; i ++ )
        for (int j = i + 1; j < n; j ++ )//枚举组合数,看两两是否有关系
            if(d[i][j] == 0 && d[j][i] == 0) return 0;
    
    return 1;
}


char get_min()
{
    for (int i = 0; i < n; i ++ )
        if (!st[i])
        {
            bool flag = true;
            for (int j = 0; j < n; j ++ )
                if (!st[j] && d[j][i])
                {
                    flag = false;
                    break;
                }
            if (flag)
            {
                st[i] = true;
                return 'A' + i;
            }
        }
}



int main ()
{
    
    while (cin >> n >> m, n || m)//多组数据
    {
        memset(g, 0, sizeof g);
        int type = 0, t;
        for (int i = 1; i <= m; i ++ )
        {
            char str[5];
            cin >> str;
            
            int a = str[0] - 'A', b = str[2] - 'A';
            
            if (type == 0)//只要type !=0 就不会更新迭代关系 后面输入的关系可能导致type从2或者1变成0了但我们记录第一次
            {
                g[a][b] = 1;
                floyd();//预处理d数组
                type = check();
                if(type != 0)  t = i;//每输入一组大小关系,就说说明迭代了一次,
            }
            
        }
        if (type == 2) printf("Inconsistency found after %d relations.\n", t);
        else if (type == 1)
        {
            printf("Sorted sequence determined after %d relations: ", t);
            memset(st, 0, sizeof st);//多组数据,因此每次用到st之前都要重置一下
            for (int i = 0; i < n; i ++ ) cout << get_min();
            printf(".\n");
        }
        else printf("Sorted sequence cannot be determined.\n");
    }
    return 0;
}

AcWing 344. 观光之旅

#include <iostream>
#include <cstring>
#include <algorithm>

const int N = 110, INF = 0x3f3f3f3f;
using namespace std;

int path[N], cnt;
int pos[N][N];
int g[N][N];//稠密图所以用邻接矩阵
int d[N][N];

int n, m;

void get_path(int i, int j)
{
    if (pos[i][j] == 0) return;
    int k = pos[i][j];
    get_path(i, k);
    path[cnt ++ ] = k;
    get_path(k, j);
}

int main()
{
    cin >> n >> m;
    memset(g, 0x3f, sizeof g);//这个真不记得了,用邻接举证存的时候需要初始化
    for (int i = 1; i <= n; i ++ ) g[i][i] = 0;//这个真不记得了,用邻接举证存的时候需要初始化
    
    for (int i = 0; i < m; i ++ )
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[a][b] = g[b][a] = min(g[a][b], c);
    }
    memcpy(d, g, sizeof d);
    
    int res = INF;
    for (int k = 1; k <= n; k ++ )//我不知道为什么path记录要放在floyd前面
    {
        //path记录
        //这里不超过k其一原因是因为定义强制k为环上最大节点,
        //其次,当前最大循环第k次的时候,默认环上的结点已经有k了,
        //而且这里要保证三个点需要互异,因此i和j不同,且都要不等于k。
        //不然就会有两个点之间形成的环了。
        for (int i = 1; i < k; i ++ )
            for (int j = i + 1; j < k; j ++ )
            {
                if (res > (long long)d[i][j] + g[j][k] + g[k][i])
                {
                    res = d[i][j] + g[j][k] + g[k][i];
                    cnt = 0;//每次更新path都要重置cnt
                    path[cnt ++ ] = k;
                    path[cnt ++ ] = i;
                    get_path(i, j);
                    path[cnt ++ ] = j;
                }
            }
        //floyd
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ ) 
                if (d[i][j] > d[i][k] + d[k][j])
                {
                    d[i][j] = d[i][k] + d[k][j];
                    pos[i][j] = k;//更新的同时记录通过哪个点转移的状态
                }
                
    }
    
    if (res == INF) cout << "No solution.";
    else 
    {
        for(int i = 0; i < cnt; i ++ ) cout << path[i] << " ";
    }
        
    return 0;
}

AcWing 345. 牛站

离散化 (只要用到200个点,但是题目给的点编号是1-1000)+ 倍增(快速幂)+ flyod变式(将递推公式改变了)
能用快速幂的原因是递推公式里面的两端路径两两之间相互独立,用结合律就可以用快速幂。矩阵乘法能用快速幂的原因也是矩阵乘法中两两矩阵之间具有结合律
帮助理解的博客1
帮助理解的博客2文章来源地址https://www.toymoban.com/news/detail-492894.html

#include <iostream>
#include <cstring>
#include <map>

using namespace std;

const int N = 1010;//这里N是点数,不是题目给的边数

int k, m, S, E;
int n;//离散化后点的数量

int g[N][N];
int res[N][N];//相当于之前的d数组

                                              //好像是二维数组传参必须这样
void floyd(int c[][N], int a[][N], int b[][N])//我不知道为什么这里第二维必须要明确开N,否则编译报错
{
    static int temp[N][N];temp数组作为a数组和b组数相乘的结果,缓冲结果
    memset(temp, 0x3f, sizeof temp);
    
    for (int k = 1; k <= n; k ++ )
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
                temp[i][j] = min(temp[i][j], a[i][k] + b[k][j]);
    memcpy(c, temp, sizeof temp);//不能sizeof c,因为c只是一个指针在这里 
                                                    
   // cout << sizeof c << " " << sizeof temp;// sizeof c = 二维数组的指针 8
                                           //sizeof temp = 二维数组的大小40804008
}

void qmi()
{
    memset(res, 0x3f, sizeof res);
    for(int i=1;i<=n;i++) res[i][i]=0;//除了i->i是经过1条边位0,i到其它点都是经过0条边距离为0x3f,这样我们保持基数是0这样结合律的时候才正确
    while(k)
    {
        if (k & 1) floyd(res, res, g);//结合律 res = res * g, 
                                      //如果这一位是1的话,res就结合上这个结果
                                      
        floyd(g, g, g);//倍增g = g * g
        k >>= 1;
    }
}

int main ()
{
    cin >> k >> m >> S >> E;
    map<int, int> id;//int - int去离散化题目给的下标
    
    id[S] = ++ n, id[E] = ++ n;//题目说了数据保证一定有解,所以就没写代码的健壮性判断了,id.count(S);
    S = id[S], E = id[E];
    
    memset(g, 0x3f, sizeof g);//这里不需要将g[i][i]初始化为0,因为题目说了至少经过1条边(2≤N≤106)
                              //如果没有i->i的边的话,i->i就是正无穷,只能通过自环从i到i
    for (int i = 0; i < m; i ++ )
    {
        int a, b, c;
        cin >> c >> a >> b;//题目很坑,先输入边长的
        if(!id.count(a)) id[a]=++n;
        if(!id.count(b)) id[b]=++n;
        a=id[a],b=id[b];
        g[a][b] = g[b][a] = min (g[a][b], c);
    }
    
    qmi();
    
    cout << res[S][E];//之前已经离散化过了S和E
    return 0;
}

到了这里,关于算法提高-图论-floyd算法及其扩展应用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • acwing算法提高之图论--最小生成树的典型应用

    本专题用来记录使用prim算法或kruskal算法求解的题目。 题目1 :1140最短网络 C++代码如下, 题目2 :1141局域网 C++代码如下, 题目3 :1142繁忙的都市 C++代码如下, 题目4 :1143联络员 C++代码如下, 题目5 :1144连接格点 C++代码如下,

    2024年04月27日
    浏览(27)
  • 【图论】Floyd算法

     Floyd算法,也称为Floyd-Warshall算法,是一种用于解决所有节点对最短路径问题的动态规划算法。它可以在有向图或带权图中找到任意两个节点之间的最短路径。 Floyd算法的基本思想是通过中间节点逐步优化路径长度。它使用一个二维数组来存储任意两个节点之间的最短路径长

    2024年02月11日
    浏览(29)
  • 图论及其应用(匈牙利算法)---期末胡乱复习版

    T1:从下图中给定的 M = {x1y4,x2y2,x3y1,x4y5},用 Hungariam算法【匈牙利算法】 求出图中的 完美匹配 ,并写出步骤。 关于匈牙利算法: 需要注意的是,匈牙利算法仅适用于 二分图 ,并且能够找到完美匹配。 什么是 交替路 ?从一个未匹配点出发,依次经过非匹配边–匹配边

    2024年02月01日
    浏览(56)
  • 搜索与图论2.2-Floyd算法

    (Floyd) 算法是一种可以快速求解图上所有顶点之间最短路径的算法。 (Bellman-Ford) 和 (Dijkstra) 算法求解的都是从一个起始点开始的最短路。如果想要求解图中所有顶点之间的最短路,就需要枚举每个点做为起点,这样十分低效。 (Floyd) 算法(也称 (Floyd-Warshall) 算法)处理用

    2024年02月08日
    浏览(23)
  • 算法——图论——最短路径——Floyd / 传递闭包

    目录  Floyd-Warshall(弗洛伊德)算法 传递闭包 一、试题 算法训练 盾神与离散老师2    求所有顶点到所有顶点的最短路径问题 弗洛伊德算法(Floyd-Warshall algorithm)是一种用于寻找图中所有顶点对之间最短路径的动态规划算法。 该算法可以处理带有负权边但不含负权环的加权

    2024年02月20日
    浏览(29)
  • 算法——弗洛伊德算法(Floyd-Warshall)(图论)(c++)

    (蒟蒻的第四篇文章,希望dalao勿喷) (希望没问题) 声明: 1.本人变量定义的名称很low 2.本人用的方法也很low 3.但我觉得文章应该不low  (盲目自信) 第四篇文章讲讲Floyd算法 Floyd算法是一种寻找最短路径的常见算法,其特点是: 短,好理解(虽然其他算法也挺好理解的

    2023年04月09日
    浏览(21)
  • 图论:最短路(dijkstra算法、bellman算法、spfa算法、floyd算法)详细版

    终于是学完了,这个最短路我学了好几天,当然也学了别的算法啦,也是非常的累啊。 话不多说下面看看最短路问题吧。 最短路问题是有向图,要求的是图中一个点到起点的距离,其中我们要输入点和点之间的距离,来求最短路。 下面分为几类题目: 单源汇最短路--一个起

    2024年01月21日
    浏览(24)
  • 【图论C++】Floyd算法(多源最短路径长 及 完整路径)

    UpData Log👆 2023.9.29 更新进行中 Statement0🥇 一起进步 Statement1💯 有些描述可能不够标准,但能达其意 常见的有: DJ算法 、 Floyd算法 、 A*算法 、 Bellman-Ford 算法 、 SPFA算法 其中 A*算法 是 DJ算法 的plus版, SPFA算法 是 Bellman-Ford 算法 的plus版 算法名称 DJ算法 Floyd算法 SPFA算法

    2024年02月19日
    浏览(26)
  • 扩展的多曝光图像合成算法及其在单幅图像增强中的应用。

    在拉普拉斯金字塔在多图HDR算法中的应用以及多曝光图像的融合算法简介一文中提高的Exposure Fusion算法,是一种非常优秀的多曝光图片合成算法,对于大部分测试图都能获取到较为满意的结果,但是也存在着两个局限性: 1、存在着Out-of-range Artifact;         2、存在着low f

    2024年02月08日
    浏览(30)
  • 【算法基础:搜索与图论】3.4 求最短路算法(Dijkstra&bellman-ford&spfa&Floyd)

    关于最短路可见:https://oi-wiki.org/graph/shortest-path/ 无向图 是一种 特殊的 有向图。(所以上面的知识地图上没有区分边有向还是无向) 关于存储:稠密图用邻接矩阵,稀疏图用邻接表。 朴素Dijkstra 和 堆优化Dijkstra算法的 选择就在于图 是 稠密的还是稀疏的。 算法步骤: 有一

    2024年02月16日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包