第三章 图论 No.3 flody之多源汇最短路,传递闭包,最小环与倍增

文章目录

      • 多源汇最短路:1125. 牛的旅行
      • 传递闭包:343. 排序
      • 最小环:344. 观光之旅
      • 345. 牛站

flody的四个应用:

  1. 多源汇最短路
  2. 传递闭包
  3. 找最小环
  4. 恰好经过k条边的最短路 倍增

多源汇最短路:1125. 牛的旅行

1125. 牛的旅行 - AcWing题库
image.png

直径概念:同一连通块中,两个距离最远的点之间的距离
如何求直径?由于图中存在着两个连通块,所以直接对全图做一个flody,就能更新出任意两点间的距离,距离大于正无穷的一半时,说明两点处于不同连通块中
题目要连接两个连通块,并计算所有连接方法下,原连通块与新连通块中,最大直径的最小值

可以枚举所有的连接方式,维护出新连通块的直径最小值,将其与原连通块的两个直径比较,取三者的最小值即可
假设连接了属于不同连通块的i和j,那么经过这条边的直径等于get_dis(i, j) + dmax(i) + dmax(j),其中get_dis表示两点间的距离,dmax(i)表示在原连通块中,i与距离i最远的点的距离
那么新连通块的直径是原连通块的直径与经过连接两连通块的边的直径中的最大值

最终要在原连通块的直径与新连通块的直径最大值中取min
在计算新连通块的直径最大值时,需要在原连通块与当前新连通块的直径中取max,由于每中不同连接方式都要与原连通块的直径取max,我们可以放到最后在与之取max
先计算经过连接两连通块的边的直径的最大值,在与原连通块的直接取max

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

#define x first
#define y second

using namespace std;

typedef pair<double, double> PDD;

const int N = 155;
const double INF = 1e20;

int n;
PDD q[N];
double d[N][N];
double maxd[N];
char g[N][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)
                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 ++ )
            if (d[i][j] > INF / 2)
                r2 = min(r2, maxd[i] + maxd[j] + get_dist(q[i], q[j]));
cout << r1 << ' ' << r2 << endl;
    printf("%.6lf\n", max(r1, r2));

    return 0;
}

传递闭包:343. 排序

343. 排序 - AcWing题库
image.png

将简洁相连的点连接起来,成为传递闭包
用flody可以在 O ( n 3 ) O(n^3) O(n3)的时间复杂度内计算出传递闭包
用邻接矩阵g存储图,传递闭包保存在矩阵d上
g[i][j]为1,表示存在一条从i到j的边,g[i][j]为0表示不存在
初始化:d[i][j] = g[i][j]
flody的更新换为:
d[i][j] |= d[i][k] && d[k][j]

image.png

题目中的小于关系就是一条边,每次读取一个小于关系,就在图中添加一条边,然后求传递闭包
三种情况:

  1. 矛盾:此时d[i][[i] = 1,表示i存在自环。因为d[i][j] == 1 && d[j][i] == 1,求完传递闭包后d[i][i] = 1
  2. 情况未确定,d[i][j]d[j][i]都为0,表示i和j之间没有边,即没有小于关系
  3. 情况确定,遍历完d数组,无以上情况,此时情况确定

当情况确定时,如何按小于关系输出变量? O ( n 2 ) O(n^2) O(n2)地暴力搜索所有点,将已经输出的变量进行标记,若当前点是某一条边的终点并且起点未被标记,说明存在小于当前变量的变量,且未被输出
若当前变量不是任意一条边的终点或者起点已经被标记,那么输出该变量并标记

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

using namespace std;

const int N = 26;

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

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])
            return 2;

    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < i; j ++ )
            if (!d[i][j] && !d[j][i])
                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)
            {
                g[a][b] = 1;
                floyd();
                type = check();
                if (type) t = i;
            }
        }

        if (!type) puts("Sorted sequence cannot be determined.");
        else if (type == 2) printf("Inconsistency found after %d relations.\n", t);
        else
        {
            memset(st, 0, sizeof st);
            printf("Sorted sequence determined after %d relations: ", t);
            for (int i = 0; i < n; i ++ ) printf("%c", get_min());
            printf(".\n");
        }
    }

    return 0;
}

最小环:344. 观光之旅

344. 观光之旅 - AcWing题库
image.png

如何求第k类的最小环?
思考flody的三重循环,在第一重k循环时,我们已经知道从i到j只经过1~k-1这些点的最短路径
若i,j,k三者能构成环,那么i和k直接相连,i和j也直接相连
image.png

此时i,j,k构成的最小环的长度就等于d[i][j] + g[i][k] + g[k][j]
d[i][j]为i到j的最短距离
所以在循环k时,就可以枚举所有的i和j,得到包含i,j,k三点的最小环,在这些最小环中取min即可

此外,还需要求具体方案
只需要在更新的时候:d[i][j] > d[i][k] + d[k][j]时,记录i到j的最短路经过了k即可,即pos[i][j] = k
求i到j的最短路时,采用递归的方式,get_path(i, j),该函数将顺序输出i到j的最短路中,除了i和j的所有中间点
get_path(i, j),通过pos[i][j]的值,将i到j划分称i到k到j,递归get_path(i, k)get_path(k, j),直到pos[i][j]为0,说明i到j之间无之间点,即两点之间相连

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

typedef long long LL;
const int N = 110, M = 20010, INF = 0x3f3f3f3f;
int g[N][N], d[N][N];
int path[N], cnt;
int pos[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()
{
    scanf("%d%d", &n, &m);
    memset(g, 0x3f, sizeof(g));
    for (int i = 1; i <= n; ++ i ) g[i][i] = 0;
    for (int i = 1; i <= m; ++ i )
    {
        int x, y, d;
        scanf("%d%d%d", &x, &y, &d);
        g[x][y] = g[y][x] = min(g[x][y], d);
    }
    
    memcpy(d, g, sizeof(g));
    int res = INF;
    for (int k = 1; k <= n; ++ k )
    {
        for (int i = 1; i < k; ++ i  )
            for (int j = i + 1; j < k; ++ j )
            {
                if (res > (LL)d[i][j] + g[i][k] + g[k][j])
                {
                    res = d[i][j] + g[i][k] + g[k][j];
                    cnt = 0;
                    path[cnt ++ ] = k; // 从k开始记录环
                    path[cnt ++ ] = i;
                    get_path(i, j);
                    path[cnt ++ ] = j;
                }
            }

        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) puts("No solution.");
    else for (int i = 0; i < cnt; ++ i ) printf("%d ", path[i]);
        
    return 0;
}

一些需要注意的地方:res > (LL)d[i][j] + g[i][k] + g[k][j]
不开LL的话,可能三个INF相加会导致爆int
枚举最小环时,j从i+1开始,保证j比i的同时,也保证最小环中至少有三个点


没看懂,先跳过

345. 牛站

345. 牛站 - AcWing题库
image.png

flody的变形,表示的状态发生变化, f ( k , i , j ) f(k, i, j) f(k,i,j)表示从i到j,恰好经过k条边的最短路
d [ a + b , i , j ] = d [ a , i , k ] + d [ b , k , j ] d[a+b, i, j] = d[a, i, k] + d[b, k, j] d[a+b,i,j]=d[a,i,k]+d[b,k,j]
从i到j恰好经过a+b条边的最短路径,假设中间点为k,将路径划分称两段,经过a条边从i到k,经过b条边从k到j。两段分别取最短路径,相加得到我们需要的最短路径
枚举所有的k,取min后就能得到 d [ a + b , i , j ] d[a+b, i, j] d[a+b,i,j]
枚举所有的k后,枚举不同的i和j,转换成代码就是flody的形式

image.png

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数学建模—多元线性回归分析

第一部分&#xff1a;回归分析的介绍 定义&#xff1a;回归分析是数据分析中最基础也是最重要的分析工具&#xff0c;绝大多数的数据分析问题&#xff0c;都可以使用回归的思想来解决。回归分析的人数就是&#xff0c;通过研究自变量X和因变量Y的相关关系&#xff0c;尝试去解释…

医疗知识图谱问答 ——Neo4j 基本操作

前言 说到问答机器人&#xff0c;就不得不说一下 ChatGPT 啦。一个预训练的大预言模型&#xff0c;只要是人类范畴内的知识&#xff0c;似乎他回答得都井井有条&#xff0c;从写文章到写代码&#xff0c;再到解决零散琐碎的问题&#xff0c;不光震撼到我们普通人&#xff0c;就…

本地 shell无法连接centos 7 ?

1、首先检查是否安装ssh服务&#xff1b; yum list installed | grep openssh-server# 没有安装尝试安装下 yum install openssh-server 2、检查ssh服务是否开启 systemctl status sshd.service# 未开启&#xff0c;开启下 systemctl start sshd.service # 将sshd 服务添…

MySQL多表查询 (超详细)

一、多表关系 项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个表结构之间也存在着各种联系&#xff0c;基本上分为三种: 一对多&#xff0…

类与对象【中】

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;题目大解析2 目录 &#x1f449;&#x1f3fb;类的默认6个成员函数&#x1f449;&#x1f3fb;构造…

常用HTML标签大全

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;啥技术都喜欢捣鼓捣鼓&#xff0c;喜欢分享技术、经验、生活。 &#x1f60e;人生感悟&#xff1a;尝尽人生百味&#xff0c;方知世间冷暖。 文章目录 一.HTML介绍二.HTML使用2.1.…

Ubuntu 23.04 作为系统盘的体验和使用感受

1.为啥主系统装了Ubuntu 由于公司发电脑了&#xff0c;我自己也有一台台式电脑&#xff0c;然后也想去折腾一下Ubuntu&#xff0c;就把自己的笔记本装成Ubuntu系统了&#xff0c; 我使用的是23.04的桌面版&#xff0c;带图形化界面的。我准备换回Windows 11了&#xff08;因为…

64 # 实现一个 http-server

准备工作 上一节实现了通过 commander 的配置获取到用户的参数&#xff0c;下面完成借用 promise 写成类的方法一节没有完成的任务&#xff0c;实现一个 http-server&#xff0c;https://www.npmjs.com/package/http-server&#xff0c;http-server 是一个简单的零配置命令行静…

pycharm打开terminal报错

Pycharm打开终端报错如何解决&#xff1f;估计是终端启动conda不顺利&#xff0c;需要重新设置路径。参考以下文章的做法即可。 Windows下Pycharm中Terminal无法进入conda环境和Python Console 不能使用 给pycharm中Terminal 添加新的shell&#xff0c;才可以使用conda环境 W…

HDFS中的Federation联邦机制

HDFS中的Federation联邦机制 当前HDFS体系架构--简介局限性 联邦Federation架构简介好处配置示例 当前HDFS体系架构–简介 当前的HDFS结构有两个主要的层&#xff1a; 命名空间&#xff08;namespace&#xff09; 由文件&#xff0c;块和目录组成的统一抽象的目录树结构。由n…

2配置篇:基础功能配置

前言 在上一章节中,我们学习了 NestJS CLI 的用法,得到了一套基础的项目工程。最开始做项目对比的时候也提到过,NestJS 作为一款自定义程度较高的框架,CLI 直接提供的基础功能虽然并不完善,但同时也为开发者提供了非常多的内置或配套的功能例如高速缓存、日志拦截、过滤器…

SocialFi 的开发中如何利用 NFTScan API 获取 NFT 数据

SocialFi 作为社交媒体与 Web3 的创新融合&#xff0c;致力于构建更加开放去中心化的社交平台。它赋能用户拥有数据控制权、实现内容价值&#xff0c;并通过代币经济建立起激励与治理机制&#xff0c;这正是 Web3 社交的独特魅力所在。SocialFi 为我们描绘了一个更加用户驱动、…

回顾 OWASP 机器学习十大风险

日复一日&#xff0c;越来越多的机器学习 (ML) 模型正在开发中。机器学习模型用于查找训练数据中的模式&#xff0c;可以产生令人印象深刻的检测和分类能力。机器学习已经为人工智能的许多领域提供了动力&#xff0c;包括情感分析、图像分类、面部检测、威胁情报等。 数十亿美…

《零基础入门学习Python》第076讲:GUI的终极选择:Tkinter13

这节课我们来学习 Tkinter 的布局管理器&#xff0c;那什么是布局管理器呢&#xff1f;说白了&#xff0c;就是用于管理你的组件如何排列。Tkinter 提供了 3 大布局管理器&#xff1a;pack、grid 和 place。 pack 是按添加顺序排列组件grid 是按行/列形式排列组件place 则允许…

秋招算法备战第37天 | 738.单调递增的数字、968.监控二叉树、贪心算法总结

738. 单调递增的数字 - 力扣&#xff08;LeetCode&#xff09; 这个问题是关于找到一个小于或等于给定数字n的最大单调递增数字。 我们可以将数字n转换为字符数组&#xff0c;然后从左到右扫描&#xff0c;寻找第一个违反单调递增条件的位置。一旦找到这样的位置&#xff0c;…

uni-app:实现列表单选功能

效果图&#xff1a; 核心解析&#xff1a; 一、 <view class"item_all" v-for"(item, index) in info" :key"index"><view classposition parameter-info text-over :classitem.checked?"checked_parameter":""…

在java中操作redis_Data

1.引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency> 2.配置Redis数据源 redis:host: ${sky.redis.host}port: ${sky.redis.port}password: ${sk…

驱动工作原理

驱动原理 在Linux操作系统中&#xff0c;硬件驱动程序中实现对硬件直接操作&#xff0c;而用户空间&#xff0c;通过通用的系统调用接口&#xff08;open() 打开相应的驱动设备,ioctl()控制相应的功能等&#xff09;&#xff0c;实现对硬件操作&#xff0c;应用程序没有直接操作…

EdgeBox_tx1_A200 PyTorch v1.9.0 环境部署

大家好&#xff0c;我是虎哥&#xff0c;今天远程帮助几个小伙伴在A200 控制器上安装PyTorch v1.9.0 torchvision v0.10.0&#xff0c;中间也是经历了很多波折&#xff0c;当然&#xff0c;大部分是网络问题和版本适配问题&#xff0c;所以完事后&#xff0c;将自己完整可用的过…

分布式Redis详解

目录 前言安装redis的俩种方法Redis 与 MySQL的区别Redis可以实现那些功能Redis常用的数据类型有序列表的底层是如何实现的?什么是跳跃表 Redis在Spring中的使用 前言 Redis我们最近学习必备工具之一了, 接下来我们将讲解Redis的简单应用 ,以及相关原理 安装redis的俩种方法…