第三章 图论 No.6负环之01分数规划与特殊建图方式

news2024/10/5 17:17:01

文章目录

      • 裸题:904. 虫洞
      • 01分数规划:361. 观光奶牛
      • 特殊建图与01分数规划+trick:1165. 单词环

裸题:904. 虫洞

904. 虫洞 - AcWing题库
image.png

// 虫洞是负权且单向边,道路是正权且双向边,题目较裸,判断有无负环即可
#include <iostream>
#include <cstring>
using namespace std;

const int N = 510, M = 6010;
int h[N], e[M], ne[M], w[M], idx;
int n, m, k;
int dis[N], cnt[N];
int q[N];
bool st[N];

void add(int x, int y, int d)
{
    e[idx] = y, ne[idx] = h[x], w[idx] = d, h[x] = idx ++ ;
}

bool spfa()
{
    int tt = 0, hh = 0;
    memset(cnt, 0, sizeof(cnt));
    memset(dis, 0, sizeof(dis));
    memset(st, 0, sizeof(st));
    for (int i = 1; i <= n; ++ i ) st[i] = true, q[tt ++ ] = i;
    while (hh != tt)
    {
        int x = q[hh ++ ];
        if (hh == N) hh = 0;
        st[x] = false;
        for (int i = h[x]; i != -1; i = ne[i])
        {
            int y = e[i];
            if (dis[y] > dis[x] + w[i])
            {
                cnt[y] = cnt[x] + 1;
                if (cnt[y] >= n) return true;
                dis[y] = dis[x] + w[i];
                if (!st[y]) 
                {
                    st[y] = true;
                    q[tt ++ ] = y;
                    if (tt == N) tt = 0;
                }
            }
        }
    }
    return false;
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T -- )
    {
        memset(h, -1, sizeof(h));
        idx = 0;
        scanf("%d%d%d", &n, &m, &k);
        int x, y, d;
        for (int i = 0; i < m; ++ i )
        {
            scanf("%d%d%d", &x, &y, &d);
            add(x, y, d), add(y, x, d);
        }
        for (int i = 0; i < k; ++ i )
        {
            scanf("%d%d%d", &x, &y, &d);
            add(x, y, -d);
        }
        if (spfa()) puts("YES");
        else puts("NO");
    }
    return 0;
}

image.png
这个==真的服,调半天,还有,邻接表的大小又设置错了


01分数规划:361. 观光奶牛

361. 观光奶牛 - AcWing题库
image.png

在图论问题中,所有形如:某个部分之和除以某个部分之和最大的问题,被称为01分数规划,通常使用二分解决这类问题
根据题意,这道题的答案范围在 ( 0 , 1000 ] (0, 1000] (0,1000]中,我们需要二分这个区间找到答案
若点权之和/边权之和大于等于mid,则说明答案在 [ m i d , r ] [mid, r] [mid,r]之间
反之,点权之和/边权小于mid,则说明答案在 [ l , m i d ] [l, mid] [l,mid]之间
根据这个二段性,我们能二分出ans,使得边权之和/边权之和的最大值 = ans

现在的问题是check如何实现?
整理不等式,如下图:
image.png

一个常用的技巧:若图中的环既有点权又有边权,那么可以将点权加到出边或者入边上
那么不等式的求和可以提到外面,结合这个技巧,将点权和边权结合
若一条边由x->y,权值为w,那么将其权值设置为 f x − m i d ∗ w f_x-mid*w fxmidw f x f_x fx为x的点权
问题就转换成了图中是否存在一个正环?
求正环只要修改三角不等式即可:dis[y] < dis[x] + w[i]

总结下:check判断图中是否存在一个环,其点权之和/边权之和大于等于mid,转换成图中是否存在一个正环(或权值和为0的环),若存在,则l = mid,否则r = mid,

  1. 思考题目的二段性
  2. 根据不等式重置边/点权
  3. 根据不等式判断题目的具体问题:负环/最小生成树/最短路
#include <iostream>
#include <cstring>
using namespace std;

const int N = 1010, M = 5010;
int h[N], e[M], ne[M], w[M], idx;
int f[N];
double dis[N];
int cnt[N]; bool st[N];
int q[N];

int n, m;

void add(int x, int y, int d)
{
    e[idx] = y, ne[idx] = h[x], w[idx] = d, h[x] = idx ++ ;
}

bool check(double mid)
{
    memset(dis, 0, sizeof(dis));
    memset(cnt, 0, sizeof(cnt));
    int tt = 0, hh = 0;
    
    for (int i = 1; i <= n; ++ i ) st[i] = true, q[tt ++ ] = i;
    while (hh != tt)
    {
        int x = q[hh ++ ];
        if (hh == N) hh = 0;
        st[x] = false;
        for (int i = h[x]; i != -1; i = ne[i])
        {
            int y = e[i];
            if (dis[y] <= dis[x] + f[x] - mid * w[i])
            {
                dis[y] = dis[x] + f[x] - mid * w[i];
                cnt[y] = cnt[x] + 1;
                if (cnt[y] >= n) return true;
                if(!st[y])
                {
                    st[y] = true;
                    q[tt ++ ] = y;
                    if (tt == N) tt = 0;
                }
            }
        }
    }
    return false;
}

int main()
{
    memset(h, -1, sizeof(h));
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++ i ) scanf("%d", &f[i]);
    int x, y, d;
    for (int i = 0; i < m; ++ i )
    {
        scanf("%d%d%d", &x, &y, &d);
        add(x, y, d);
    }
    
    double l = 0, r = 1000;
    while (r - l > 1e-4)
    {
        double mid = (l + r) / 2;
        if (check(mid)) l = mid;
        else r = mid;
    }
    
    printf("%.2lf\n", r);
    return 0;
}

debug:点权需要从数组1号下标开始读取


特殊建图与01分数规划+trick:1165. 单词环

1165. 单词环 - AcWing题库
image.png

估算一下这题的数据量,如果按照题意建图,不仅爆空间还会爆时间,所以这题需要考虑其他建图方式
image.png

题目给定的建图方式是:单词为点,若两单词能相连,那么边的权值为1
考虑新的建图方式,以单词的前两个字符为起点,最后两个字符为终点,建立一条有向边,权值为单词的长度。这种建图方式中,点的数量最多为26 * 26,边的数量为 1 0 5 10^5 105

其次,题目要求环中所有单词的长度之和 / 环中的单词数量最大,显然是01分数规划
二分答案,答案的范围是 ( 0 , 1000 ] (0, 1000] (0,1000],最大的答案为每个单词长度都是1000,而最小的答案0是取不到的,最小的情况应该是1,0用来表示无解
整理不等式,重新设置边权为 w i − 1 ∗ m i d w_i - 1 * mid wi1mid,1是由环中点的数量累加后(第二个式子)再把累加提到外面(第三个等式)得到的
check:每次根据mid判断图中是否存在正环或零环,若存在返回true,反之返回false

trick:如果spfa更新了很多次还没有结束循环,那么有极大概率可以认为图中存在环,这里设置阈值为10000(点数的十几倍),当循环次数超过该值时,直接认为图中存在环、
不过这样的trick在正规比赛中不会出现

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

const int N = 27 * 27, M = 1e5 + 10;
int h[N], e[M], ne[M], w[M], idx;
double dis[N];
int cnt[N], q[N];
bool st[N];

void add(int x, int y, int d)
{
    e[idx] = y, ne[idx] = h[x], w[idx] = d, h[x] = idx ++ ;
}

bool check(double mid)
{
    memset(dis, 0, sizeof(dis));
    memset(cnt, 0, sizeof(cnt));
    int tt = 0, hh = 0, count = 0;
    for (int i = 0; i < N - 1; ++ i ) q[tt ++ ] = i, st[i] = true;
    while (hh != tt )
    {
        int x = q[hh ++ ];
        if (hh == N) hh = 0;
        st[x] = false;
        for (int i = h[x]; i != -1; i = ne[i])
        {
            int y = e[i];
            if (dis[y] <= dis[x] + w[i] - mid)
            {
                cnt[y] = cnt[x] + 1;
                if (cnt[y] >= N) return true;
                if (++ count >= 10000) return true;
                dis[y] = dis[x] + w[i] - mid;
                if (!st[y])
                {
                    st[y] = true;
                    q[tt ++ ] = y;
                    if (tt == N) tt = 0;
                }
            }
        }
    }
    return false;
}

int main()
{
    int m;
    char str[1010];
    while (scanf("%d", &m), m)
    {
        memset(h, -1, sizeof(h));
        idx = 0;
        for (int i = 0; i < m; ++ i )
        {
            scanf("%s", str);
            int len = strlen(str);
            if (len >= 2)
            {
                int x = (str[0] - 'a') * 26 + str[1] - 'a';
                int y = (str[len - 2] - 'a') * 26 + str[len - 1] - 'a';
                add(x, y, len);
            }
        }
        
        double l = 0, r = 1000;
        while (r - l > 1e-4)
        {
            double mid = (l + r) / 2;
            if (check(mid)) l = mid;
            else r = mid;
        }
        
        if (r < 1e-4) puts("No solution");
        else printf("%.2lf\n", r);
    }
    return 0;
}

debug:dis数组的类型开成int,想着边的权值为整数,int就行,然而边权被重置,类型是浮点数

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

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

相关文章

Linux CentOS安装NVIDIA GPU驱动程序和NVIDIA CUDA工具包

要在CentOS上安装NVIDIA驱动程序和NVIDIA CUDA工具包&#xff0c;您可以按照以下步骤进行操作&#xff1a; 1. 准备工作&#xff1a; 确保您的系统具有兼容的NVIDIA GPU。您可以在NVIDIA官方网站上查找支持CUDA的GPU型号列表。如果您之前已经安装了Nouveau驱动程序并禁用了它…

【基于DAVE的英飞凌XMC4200的RS485通讯】

设备明细&#xff1a; 单片机&#xff1a;英飞凌开发板XMC4200 Platform2Go&#xff1b; 开发软件&#xff1a; DAVE; 测试设备&#xff1a;示波器。 调试PIN TX: PIN 2.14 接线 TX PIN 2.14&#xff1a;接示波器信号端 GND&#xff1a;接示波器地端 Debug口USB&#xff1…

如何搭建个人的GPT网页服务

写在前面 在创建个人的 GPT网页之前&#xff0c;我登录了 Git 并尝试了一些开源项目&#xff0c;但是没有找到满足我个性化需求的设计。虽然许多收费的 GPT网页提供了一些免费额度&#xff0c;足够我使用&#xff0c;但是公司的安全策略会屏蔽这些网页。因此&#xff0c;我决定…

【开源项目--稻草】Day06

【开源项目--稻草】Day06 1. 学生提问与解答功能2. 显示create.html2.1 HomeController中代码2.2 复用网页的标签导航条 3. 创建问题发布界面3.1 富文本编辑器 4.多选下列框5.动态加载所有标签和老师6. 发布问题的业务处理 1. 学生提问与解答功能 学生提问: 提问时指定标签和回…

LeetCode-Java(02)

5. 最长回文子串 首先用start和end记录开始和结尾位置&#xff0c;遍历每一个字符&#xff0c;对于每一个字符有两种情况&#xff0c;第一种情况&#xff0c;从一个字符中心扩展&#xff0c;得到len1&#xff0c;第二种情况&#xff0c;从两个字符中心扩展&#xff0c;得到len2…

MFC第二十七天 通过动态链表实现游戏角色动态增加、WM_ERASEBKGND背景刷新的原理、RegisterClass注册窗口与框架程序开发

文章目录 通过动态链表实现游戏角色动态增加CMemoryDC.hCFlashDlg.hCFlashDlg.cpp WM_ERASEBKGND背景刷新的原理RegisterClass注册窗口与框架程序开发CFrameRegister 通过动态链表实现游戏角色动态增加 CMemoryDC.h #pragma once#include "resource.h"/*内存DC类简介…

【Shell】基础语法(二)

文章目录 一、Shell基本语法文件名代换命令代换算术代换转义字符引号 二、Shell脚本语法条件测试分支结构循环 三、总结 一、Shell基本语法 文件名代换 用于匹配的字符称为通配符&#xff08;Wildcard&#xff09;&#xff0c;如&#xff1a;* ? [ ] 具体如下&#xff1a; *…

【Datawhale AI 夏令营第二期】AI 量化模型预测挑战赛

文章目录 赛题分析赛题背景赛事任务赛题数据集评价指标 Baseline实践导入模块EDA特征工程模型训练与验证结果输出 改进 赛题分析 赛题背景 量化金融在国外已经有数十年的历程&#xff0c;而在国内兴起还不到十年。这是一个极具挑战的领域。量化金融结合了数理统计、金融理论、…

DataWhale 机器学习夏令营第二期——AI量化模型预测挑战赛 学习记录

DataWhale 机器学习夏令营第二期 学习记录一 (2023.08.06)1. 问题建模1.1 赛事数据数据集情况数据中缺失值类别和数值特征的基本分布 1.2 评价指标中间价的计算方式价格移动方向说明 1.3 线下验证 DataWhale 机器学习夏令营第二期 ——AI量化模型预测挑战赛 已跑通baseline&…

排查吞吐量和 SNR 方面的 Wi-Fi 问题

服务交付对于客户在选择品牌时要考虑很重要&#xff0c;组织依靠其网络向全球客户无缝提供服务&#xff0c;强大的网络连接对于更好的最终用户体验至关重要&#xff0c;而高质量访问的关键是两个关键指标&#xff1a; 吞吐量信噪比 &#xff08;SNR&#xff09; 为了获得更好…

解决word打字卡顿问题的方法

❤ 2023.8.5 ❤ 最近整理论文&#xff0c;本来我是wps死忠粉&#xff0c;奈何wps不支持latex公式。。。 无奈用起了word&#xff0c;但是谁想字数稍微多了一点&#xff0c;word就卡得欲仙欲死&#xff0c;打个字过去2s才显示出来&#xff0c;删除的时候都不知道自己删了几个字…

基于STM32CUBEMX驱动低压步进器电机驱动器STSPIN220(1)----套件概述

基于STM32CUBEMX驱动低压步进器电机驱动器STSPIN220----1.套件概述 套件概述样品申请特征系统控制和生态系统访问功能示意图系统框图跳线设置开发板原理图 套件概述 STM32C011F4Px_STSPIN220 是一款基于 STM32C011F4Px 的低压步进电机驱动套件。其中&#xff0c;STSPIN220 是一…

离散化的两种实现方式【sort或者map】

离散化 定义 把无限空间中有限的个体映射到有限的空间中去&#xff0c;以此提高算法的时空效率。通俗的说&#xff0c;离散化是在不改变数据相对大小的条件下&#xff0c;对数据进行相应的缩小。 适用范围&#xff1a;数组中元素值域很大&#xff0c;但个数不是很多。 比如将…

Navicat远程连接Linux的MySQL

打开Linux终端&#xff0c;进入root权限&#xff0c;用vim打开MySQL的配置文件 vim /etc/mysql/mysql.conf.d/mysqld.cnf将bind-address的值改为0.0.0.0 进入MySQL mysql -u root -p 将root用户改为允许远程登录 update user set host % where user root; 创建用户 CRE…

码出高效_第二章 | 面向对象_上

目录 一. OOP理念1. 概念辨析2. 四大特性1. 抽象2. 封装3. 继承4. 多态 二. 初识Java1. JDKJDK 5-11的重要类、特性及重大改变 2. JRE关于JVM 三. 类1. 概述2. 接口和抽象类1. 概念及相同点2. 不同点3. 总结 3. 内部类4. 访问权限控制1. 由来2. public/private/无/private3. 推…

无涯教程-Perl - endgrent函数

描述 此功能告诉系统您不再希望使用getgrent从groups文件中读取条目。 语法 以下是此函数的简单语法- endgrent返回值 此函数不返回任何值。 Perl 中的 endgrent函数 - 无涯教程网无涯教程网提供描述此功能告诉系统您不再希望使用getgrent从groups文件中读取条目。 语法以…

开源项目-私人牙医管理系统

哈喽,大家好,今天给大家带来一个开源项目-私人牙医管理系统,项目使用springboot+mysql技术实现 私人牙医管理系统的主要功能包括客户管理,医生管理,药品管理,文章管理模块 登录 客户管理 客户管理主要有客户数据,客户列表,添加客户功能 客户数据 客户列表 添加…

VIOOVI的精益生产探析:深入了解精益生产的本质

精益生产它是利用杜绝浪费和稳定、连续生产的作业流程&#xff0c;是通过系统性的结构管理、生产人员组织以及市场端的供求现状等方面的因素做对应的调整、变革。具备有一定战斗力的生产管理体系&#xff0c;可以很快的根据市场端需求做出对应的调整&#xff0c;而且实现生产过…

黑马大数据学习笔记5-案例

目录 需求分析背景介绍目标需求数据内容DBeaver连接到Hive建库建表加载数据 ETL数据清洗数据问题需求实现查看结果扩展 指标计算需求需求指标统计 可视化展示BIFineBI的介绍及安装FineBI配置数据源及数据准备 可视化展示 P73~77 https://www.bilibili.com/video/BV1WY4y197g7?…

如何使用win10专业版系统自带远程桌面公司内网电脑,从而实现居家办公?

使用win10专业版自带远程桌面公司内网电脑 文章目录 使用win10专业版自带远程桌面公司内网电脑 在现代社会中&#xff0c;各类电子硬件已经遍布我们身边&#xff0c;除了应用在个人娱乐场景的消费类电子产品外&#xff0c;各项工作也离不开电脑的帮助&#xff0c;特别是涉及到数…