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

news2024/9/26 5:23:40

文章目录

      • 多源汇最短路: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.coloradmin.cn/o/838554.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Camera之PhysicalCameraSettingsList/SurfaceMap/CameraMetadata/RequestList的关系(三十二)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

打开的idea项目maven不生效

方法一&#xff1a;CtrlshiftA&#xff08;或者help---->find action&#xff09;&#xff0c; 输入maven&#xff0c; 点击add maven projects&#xff0c;选择本项目中的pom.xml配置文件&#xff0c;等待加载........ 方法二&#xff1a;view->tools windows->mave…

使用Python将Word文档转换为PDF的方法

摘要&#xff1a; 文介绍了如何使用Python编程语言将Word文档转换为PDF格式的方法。我们将使用python-docx和pywin32库来实现这个功能&#xff0c;这些库提供了与Microsoft Word应用程序的交互能力。 正文&#xff1a; 在现实生活和工作中&#xff0c;我们可能会遇到将Word文…

软考高级架构师——2、操作系统

一、进程管理 • 进程的状态&#xff08;★&#xff09; • 进程的同步与互斥&#xff08;★★★★&#xff09; 临界资源&#xff1a;诸进程间需要互斥方式对其进行共享的资源&#xff0c;如打印机、磁带机等 临界区&#xff1a;每个进程中访问临界资源的那段代码称为临界区…

ubuntu18.04 虚拟机与主机不通,虚拟机无法上网,导致无法git clone代码

问题前置&#xff1a;修改了固定ip。 虚拟机ip&#xff1a; 虚拟机设置NAT模式&#xff1a; 主机配置网络适配器&#xff1a;分配ipv4192.168.152.2保持与虚拟机的虚拟网关192.168.152.0,192.168.152.1在同一网段。虚拟机静态ip为192.168.152.146 虚拟机&#xff0c;网关&#…

【项目 线程4】3.12生产者消费者模型 3.13条件变量 3.14信号量 C++实现生产者消费者模型

3.12生产者消费者模型 生产者消费者模型中的对象&#xff1a; 1、生产者 2、消费者 3、容器 若容器已满&#xff0c;生产者阻塞在这&#xff0c;通知消费者去消费&#xff1b;若容器已空&#xff0c;则消费者阻塞&#xff0c;通知生产者去生产。生产者可以有多个&#xff0c;消…

供水管网漏损监测,24小时保障城市供水安全

供水管网作为城市生命线重要组成部分&#xff0c;其安全运行是城市建设和人民生活的基本保障。随着我国社会经济的快速发展和城市化进程的加快&#xff0c;城市供水管网的建设规模日益增长。然而&#xff0c;由于管网老化、外力破坏和不当维护等因素导致的供水管网漏损&#xf…

RabbitMQ的安装

RabbitMQ的安装 1、Windows环境下的RabbitMQ安装步骤 使用的版本&#xff1a;otp_win64_23.2 rabbitmq-server-3.8.16 版本说明&#xff1a;https://www.rabbitmq.com/which-erlang.html#compatibility-matrix 1.1 下载并安装erlang RabbitMQ 服务端代码是使用并发式语言…

8.5作业

要求实现AB进程对话 a.A进程先发送一句话给B进程&#xff0c;B进程接收后打印 b.B进程再回复一句话给A进程&#xff0c;A进程接收后打印 c.重复1.2步骤&#xff0c;当收到quit后&#xff0c;要结束AB进程 A进程 #include<stdio.h> #include<string.h> #include&…

Linux文本三剑客---grep、sed、awk

目录标题 1、grep1.1 命令格式1.2命令功能1.3命令参数1.4grep实战演练 2、sed2.1 认识sed2.2命令格式2.3常用选项options2.4地址定界2.5 编辑命令command2.6用法演示2.6.1常用选项options演示2.6.2地址界定演示2.6.3编辑命令command演示 3、awk3.1认识awk3.2常用命令选项3.3awk…

中国中医中药元宇宙 中药材价格缘何“狂飙”

◇相比去年同期&#xff0c;有超200个常规品种涨幅高于50%&#xff0c;25个常用大宗药材涨幅超200%&#xff0c;个别品种甚至涨价4至9倍 ◇在中药材价格普遍高涨的情况下&#xff0c;部分市场仓库库存数量也较多&#xff0c;出现囤积居奇倾向 ◇“不少游资和热钱涌入中药材市场…

MyBatis查询数据库之一(概念+创建项目+基础交互)

目录 1.MyBatis是什么&#xff1f; 2.为什么学习MyBatis&#xff1f; 3. 怎么学 MyBatis 4.第⼀个MyBatis查询 4.1 添加MyBatis框架支持 4.1.1老项目添加MyBatis 4.1.2 新项目添加MyBatis 4.2 配置连接字符串和MyBatis 4.2.1 配置连接字符串 4.2.2 配置 MyBatis 中的…

小白电脑装机(自用)

几个月前买了配件想自己装电脑&#xff0c;结果最后无法成功点亮&#xff0c;出现的问题是主板上的DebugLED黄灯常亮&#xff0c;即DRAM灯亮。对于微星主板的Debug灯&#xff0c;其含义这篇博文中有说明。 根据另一篇博文&#xff0c;有两种可能。 我这边曾将内存条和主板一块…

设计模式之模板方法

一、概述 定义一个操作中的算法的骨架&#xff0c;将一些步骤延迟到子类中。 TemplateMethod使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。 二、适用性 1.一次性实现一个算法的不变的部分&#xff0c;并将可变的行为留给子类来实现。 2.各子类中公共…

数据库与数据仓库的区别及关系

数据库与数据仓库的区别及关系 数据库数据仓库异同差异联系例子 数据库 数据库是结构化信息或数据的有序集合&#xff0c;一般以电子形式存储在计算机系统中。通常由数据库管理系统 (DBMS) 来控制。它是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集…

vue v-slot指令

目录 定义语法使用场景场景一场景二场景三tips只有一个默认插槽时 定义 在Vue中&#xff0c; v-slot 指令用于定义插槽的模板内容。它用于在父组件中传递内容到子组件中的插槽。 v-slot 指令可以用于 标签或组件标签上&#xff0c;以便在子组件中使用插槽。 语法 使用 v-slo…

记录--基于css3写出的流光登录(注释超详细!)

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 完整效果 对基本的表单样式进行设置 这里设置了基本的表单样式&#xff0c;外层用了div进行包裹&#xff0c;重点是运用了两个i元素在后期通过css样式勾画出一条线没在聚焦文本框的时候线会过度成一个…

【Spring框架】Spring事务

目录 Spring中事务的实现编程式事务声明式事务Transactional 作⽤范围Transactional 参数说明注意事项Transactional ⼯作原理 MySQL 事务隔离级别Spring 事务隔离级别事务传播机制 Spring中事务的实现 Spring中事务操作分为两类&#xff1a; 1.编程式事务 2.声明式事务 编程…

c语言小知识点

文章目录 int main()与int main(void)符号常量常变量无符号赋值将占字节多的赋值给字节少的类型赋初值 表达式预处理格式符e格式符 循环for 输入长度相关输出文件管理 int main()与int main(void) int main(void) 指的是此函数的参数为空&#xff0c;不能传入参数&#xff0c;…

Streamlit的第一个应用(二)

文章目录 1 前言2 创建第一个应用 &#x1f4dd;&#x1f680;3 获取数据 &#x1f4e6;&#x1f50d;4 函数缓存&#x1f680;&#x1f50d;&#x1f4ca;5 赏析原始数据 ✨&#x1f389;6 绘制直方图 &#x1f4ca;✨7 所有乘车点的地图 &#x1f30d;&#x1f696;8 完整代码…