第三章 图论 No.6负环之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就行,然而边权被重置,类型是浮点数

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

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

相关文章

【SpringBoot学习笔记】02. yaml配置注入

yaml配置注入 yaml基础语法 说明&#xff1a;语法要求严格&#xff01; 1、空格不能省略 2、以缩进来控制层级关系&#xff0c;只要是左边对齐的一列数据都是同一个层级的。 3、属性和值的大小写都是十分敏感的。 yaml注入配置文件 1、在springboot项目中的resources目录…

32位M0核单片机XL32F003芯片特征和功能介绍

XL32F003 系列微控制器采用高性能的 32 位 ARMCortex- M0 内核&#xff0c;宽电压工作范围的MCU。嵌入高达64 Kbytes flash和8 Kbytes SRAM存储器&#xff0c;最高工作频率32 MHz。包含多种不同封装类型多款产品。芯片集成多路I2C、SPI、 USART等通讯外设&#xff0c;1路12 bit…

一招让你的Python爬虫事半功倍

在Python爬虫的世界里&#xff0c;你是否也被网站的IP封锁问题困扰过&#xff1f;别担心&#xff0c;我来教你一个简单而又有效的爬虫ip设置方法&#xff0c;让你的爬虫畅行无阻&#xff01;快来跟我学&#xff0c;让你的Python爬虫事半功倍&#xff0c;轻松搞定IP封锁问题&…

【高频面试题】微服务篇

文章目录 Spring Cloud1.Spring Cloud 5大组件有哪些&#xff1f;2.服务注册和发现是什么意思&#xff1f;Spring Cloud 如何实现服务注册发现&#xff1f;3.负载均衡如何实现的 ?4.什么是服务雪崩&#xff0c;怎么解决这个问题&#xff1f;5.微服务是怎么监控的 业务相关6.项…

【ASP.NET MVC】使用动软(三)(11)

一、问题 上文中提到&#xff0c;动软提供了数据库的基本操作功能&#xff0c;但是往往需要添加新的功能来解决实际问题&#xff0c;比如GetModel&#xff0c;通过id去查对象&#xff1a; 这个功能就需要进行改进&#xff1a;往往程序中获取的是实体的其他属性&#xff0c;比如…

Spring 容器原始 Bean 是如何创建的?

以下内容基于 Spring6.0.4。 这个话题其实非常庞大&#xff0c;我本来想从 getBean 方法讲起&#xff0c;但一想这样讲完估计很多小伙伴就懵了&#xff0c;所以我们还是一步一步来&#xff0c;今天我主要是想和小伙伴们讲讲 Spring 容器创建 Bean 最最核心的 createBeanInstan…

浅谈智能低压电动机保护控制器的研发及其应用

安科瑞 华楠 摘 要&#xff1a;低压电动机保护控制器是整套工业生产自动化电动机拖动系统中的重要的核心器件&#xff0c;可以实现工业自动化生产过程中电动机远程系统监控与控制的智能化管理&#xff0c;帮助用户及 时了解电动机的运行状况&#xff0c;为电动机设备状态分析…

宝塔Linux面板点击SSL闪退打不开?怎么解决?

宝塔Linux面板点击SSL证书闪退如何解决&#xff1f;旧版本的宝塔Linux面板确实存在这种情况&#xff0c;如何解决&#xff1f;升级你的宝塔Linux面板即可。新手站长分享宝塔面板SSL闪退的解决方法&#xff1a; 宝塔面板点击SSL证书闪退解决方法 问题&#xff1a;宝塔Linux面板…

【数学建模学习(9):模拟退火算法】

模拟退火算法(Simulated Annealing, SA)的思想借 鉴于固体的退火原理&#xff0c;当固体的温度很高的时候&#xff0c;内能比 较大&#xff0c;固体的内部粒子处于快速无序运动&#xff0c;当温度慢慢降 低的过程中&#xff0c;固体的内能减小&#xff0c;粒子的慢慢趋于有序&a…

springBean生命周期解析

本文基于Spring5.3.7 参考&#xff1a; kykangyuky Spring中bean的生命周期 阿斌Java之路 SpringBean的生命周期&#xff0c; 杨开振 JavaEE互联网轻量级框架整合开发 黑马程序员 JavaEE企业级应用开发教程 马士兵 Spring源码讲解 一. SpringBean生命周期流程图 二. 示例代码 …

第 357 场力扣周赛题解

A 故障键盘 简单模拟 class Solution { public:string finalString(string s) {string res;for (auto c: s)if (c ! i)res.push_back(c);elsereverse(res.begin(), res.end());return res;} };B 判断是否能拆分数组 区间dp&#xff1a;定义 p i , j p_{i,j} pi,j​表示子数组 n…

R语言3_安装SeurateData

环境Ubuntu22/20, R4.1 在命令行中键入&#xff0c; apt-get update apt install libcurl4-openssl-dev libssl-dev libxml2-dev libcairo2-dev libgtk-3-dev # libcairo2-dev :: systemfonts # libgtk :: textshaping进入r语言交互环境&#xff0c;键入&#xff0c; instal…

基于二进制草蝉优化算法选择特征并使用 KNN 进行训练(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 基于二进制草蝉优化算法选择特征并使用KNN&#xff08;K-Nearest Neighbors&#xff0c;K最近邻算法&#xff09;进行训练是一种…

安全基础 --- https详解 + 数组(js)

CIA三属性&#xff1a;完整性&#xff08;Confidentiality&#xff09;、保密性&#xff08;Integrity&#xff09;、可用性&#xff08;Availability&#xff09;&#xff0c;也称信息安全三要素。 https 核心技术&#xff1a;用非对称加密传输对称加密的密钥&#xff0c;然后…

分库分表之基于Shardingjdbc+docker+mysql主从架构实现读写分离 (三)

本篇主要说明&#xff1a; 1. 因为这个mysql版本是8.0&#xff0c;所以当其中一台mysql节点挂掉之后&#xff0c;主从同步&#xff0c;甚至双向数据同步都失效了&#xff0c;所以本篇主要记录下当其中的节点挂掉之后如何再次生效。另外推荐大家使用mysql5.7的版本&#xff0c;这…

ORA-12154:TNS:could not resolve the connect identifier specified

避免中文乱码 NLS_LANG: AMERICAN_AMERICA.UTF8 tnsnames.ora 所在目录 TNS_ADMIN: F:\Program\instantclient_11_2\NETWORK\ADMIN

MacBook触控板窗口管理 Swish for Mac

Swish for Mac是一款用于通过手势来控制mac应用窗口的软件&#xff0c;你可以通过这款软件在触控板上进行手势控制&#xff0c;你可以在使用前预设好不同手势的功能&#xff0c;然后就能直接通过这些手势让窗口按照你想要的方式进行变动了 Swish 支持 Haptick Feedback 震动反…

postgresql|数据库|MySQL数据库向postgresql数据库迁移的工具pgloader的部署和初步使用

前言&#xff1a; MySQL数据库和postgresql数据库之间的差异并不多&#xff0c;这里的差异指的是对SQL语言的支持两者并不大&#xff0c;但底层的东西差异是非常多的&#xff0c;例如&#xff0c;MySQL的innodb引擎概念&#xff0c;数据库用户管理&#xff0c;这些和postgresq…

ruby调试

如果下载 ruby-debug-ide gem install ruby-debug-ide vscode 下载 ruby扩展 1&#xff0c; ruby 2&#xff0c;修改launch.json

windows .gitignore 加入文件名后 依然可以从git status中看到文件问题

最近在学git&#xff0c;对着b站的视频操作&#xff0c;结果很简单的添加.gitignore文件操作&#xff0c;up主的正常隐藏&#xff0c;我的却一直出问题。 百思不得其解&#xff0c;网上各种啥啥啥清缓存都没讲到点上。 最后发现是.gitignore文件有问题&#xff0c;windows默认…