毕业!第六章 贪心(一、二)——区间问题,Huffman树,不等式与推公式

news2024/11/26 2:27:42

文章目录

    • 区间问题
      • 905. 区间选点
      • 908. 最大不相交区间数量
      • 906. 区间分组
      • 907. 区间覆盖
    • Huffman树
      • 148. 合并果子
    • 排序不等式
      • 913. 排队打水
    • 绝对值不等式
      • 104. 货仓选址
    • 推公式
      • 125. 耍杂技的牛

6.18~7.22完成算法基础的学习,剩下时间用来暴刷《算法竞赛指南》以巩固基础

区间问题

905. 区间选点

905. 区间选点 - AcWing题库
image.png

选择尽可能少的点,使得每一个区间都包含一个点

将所有区间按照右端点排序,每次选择右端点,这样当前区间就包含了一个点
由于之后的区间右端点都是大于等于当前区间右端点的,所以只要后续区间与当前区间相交,那么当前区间的右端点也被后续区间包含
若后续区间与当前区间互不相交,那么选择该区间的右端点

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

const int N = 1e5 + 10;
struct range
{
    int l ,r;
    bool operator<(const range& x)
    {
        return r < x.r;
    }
}ranges[N];

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++ i) scanf("%d%d", &ranges[i].l, &ranges[i].r);
    sort(ranges, ranges + n);
    
    int res = 0, r = -2e9;
    for (int i = 0; i < n; ++ i ) 
    {
        if (ranges[i].l > r)
        {
            r = ranges[i].r;
            res ++ ;
        }
    }
    
    printf("%d\n", res);
    return 0;
}

908. 最大不相交区间数量

908. 最大不相交区间数量 - AcWing题库
image.png

求出给定区间中,最多的互不相交区间数量

将所有区间按照右端点升序排序,遍历所有区间
记互不相交的区间中右端点的最大值为mr

  1. 若当前区间的左端点大于mr,那么当前区间与所有互不相交的区间互不相交,将其加入互不相交区间,更新mr
  2. 若当前区间的左端点小于mr,那么当前区间与互不相交的区间中某个区间相交

为什么该贪心策略能选择最多的互不相交区间?所有的区间按照右端点排序,每次选择一个区间,使之与已经选择的互不相交区间不相交。同时该区间的右端点最小,说明之后能选择的区间数量最多

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

const int N = 1e5 + 10;
struct range
{
    int l, r;
    bool operator<(const range& x)
    {
        return r < x.r;
    }
}ranges[N];

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++ i ) scanf("%d%d", &ranges[i].l, &ranges[i].r);
    sort(ranges, ranges + n);
    
    int mr = -2e9, res = 0;
    for (int i = 0; i < n; ++ i ) 
    {
        if (ranges[i].l > mr)
        {
            res ++ ;
            mr = ranges[i].r;
        }
    }
    printf("%d\n", res);
    return 0;
}

906. 区间分组

906. 区间分组 - AcWing题库
image.png

将所有的区间分组,使得每一组的区间互不相交,并且分的组尽可能少

将所有区间按左端点排序,用小堆维护所有组的右端点最大值,使得堆顶是这些最大值的最小值

  1. 若当前区间的左端点大于堆顶,说明当前区间可以加入所有组中,右端点最大值最小的一组,加入后用当前区间的右端点更新该组右端点最大值
  2. 若当前区间的左端点小于等于堆顶,说明所有组中都存在一个区间 [ l , r ] [l, r] [l,r],l小于等于左端点并且r大于等于左端点。即区间重叠产生了冲突,当前区间无法加入任意一组区间,只能将当前区间放入一个新的组
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

const int N = 1e5 + 10;
struct range
{
    int l, r;
    bool operator<(const range& x)
    {
        return l < x.l;
    }
}ranges[N];

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++ i ) scanf("%d%d", &ranges[i].l, &ranges[i].r);
    sort(ranges, ranges + n);
    priority_queue<int, vector<int>, greater<int>> q;
    
    
    for (int i = 0; i < n; ++ i )
    {
        if (q.empty() || ranges[i].l <= q.top()) // 开新组
            q.push(ranges[i].r);
        else 
        {
            q.pop();
            q.push(ranges[i].r);
        }
    }
    printf("%d\n", q.size());
    
    return 0;
}

907. 区间覆盖

907. 区间覆盖 - AcWing题库
image.png

给定区间 [ s , t ] [s, t] [s,t],用最少的区间覆盖给定区间
将所有区间按照左端点排序

  1. 对于所有左端点小于等于s的区间,选择右端点最大的区间
  2. 用该区间的右端点更新s,即 s = r s=r s=r

重复以上两个步骤,直到 s > = t s >= t s>=t,此时 [ s , t ] [s, t] [s,t]区间被完全覆盖,所以重复次数就是需要的最少区间数量
其中有两个无解的情况:

  1. 对于所有左端点小于等于s的区间,最大的右端点小于等于s
  2. 所有的区间更新完, s < t s < t s<t

若遇到第一种情况直接退出更新,否则可能陷入死循环

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

const int N = 1e5 + 10;
struct range
{
    int l, r;
    bool operator<(const range& x)
    {
        return l < x.l;
    }
}ranges[N];

int main()
{
    int s, t, n;
    scanf("%d%d%d", &s, &t, &n);
    for (int i = 0; i < n; ++ i ) scanf("%d%d", &ranges[i].l, &ranges[i].r);
    sort(ranges, ranges + n);
    
    int i = 0, r = -2e9, res = 0;
    bool flag = false;
    while (i < n)
    {
        while (i < n && ranges[i].l <= s)
        {
            r = max(r, ranges[i].r);
            i ++ ;
        }
        if (r <= s && s != t) break;
        s = r;
        res ++ ;
        if (s >= t) 
        {
            flag = true;
            break;
        }
    }
    
    if (flag) printf("%d\n", res);
    else puts("-1");
    
    return 0;
}

debug:给定区间的s和t可能相等,此时右端点最大值被更新成s时不能直接break,所以这里要特判一下:if (r <= s && s != t) break;


Huffman树

148. 合并果子

148. 合并果子 - AcWing题库
image.png

经典Huffman问题,节点权值与根节点的距离具有负相关性,权值越大的节点离根节点的距离越近,权值越小的节点离根节点的距离越远,此时合并果子消耗的体力最小
所有叶子节点乘以其到根节点的距离累加,为消耗的总体力值

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

priority_queue<int, vector<int>, greater<int>> q;

int main()
{
    int n, x;
    scanf("%d", &n);
    
    for (int i = 0; i < n; ++ i ) 
    {
        scanf("%d", &x);
        q.push(x);
    }
    
    int res = 0;
    while (q.size() > 1)
    {
        int a = q.top(); q.pop();
        int b = q.top(); q.pop();
        res += a + b;
        q.push(a + b);
    }
    
    printf("%d\n", res);
    return 0;
}

排序不等式

913. 排队打水

913. 排队打水 - AcWing题库
image.png

打水时间短的人排在前面,长的人排在后面,这样总时间最小
因为第i个人打水,后面n-i个人都要等待他打水结束,有等式:
t 1 ( n − 1 ) + t 2 ∗ ( n − 2 ) + . . . + t i ( n − ( n − 1 ) ) t_1(n-1)+t_2*(n-2)+...+t_i(n-(n-1)) t1(n1)+t2(n2)+...+ti(n(n1))
前面的数乘以的数较大,后续的数乘以的数较小,t乘以的数从大到小,要使得结果最小,就要使t从小到大

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

const int N = 1e5 + 10;
int a[N];

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++ i ) scanf("%d", &a[i]);
    sort(a, a + n);
    long long res = 0;
    for (int i = 0; i < n - 1; ++ i )
        res += a[i] * (n - 1 - i);
    
    printf("%lld\n", res);
    
    return 0;
}

绝对值不等式

104. 货仓选址

104. 货仓选址 - AcWing题库
image.png

绝对值不等式:
∣ x − a ∣ + ∣ x − b ∣ > = ∣ a − b ∣ |x-a|+|x-b|>=|a-b| xa+xb>=ab
在x建立一个货仓,使得它离其他商店最近,需要使式子最小:
∣ x 1 − x ∣ + ∣ x 2 − x ∣ + . . . + ∣ x n − 1 − x ∣ + ∣ x n − x ∣ |x_1-x|+|x_2-x|+...+|x_{n-1}-x|+|x_n-x| x1x+x2x+...+xn1x+xnx
将首尾两个式子看成一组:
( ∣ x 1 − x ∣ + ∣ x n − x ∣ ) + . . . + ( ∣ x 2 − x ∣ + ∣ x n − 1 − x ∣ )   ( 1 ) (|x_1-x|+|x_n-x|)+...+(|x_2-x|+|x_{n-1}-x|)\ (1) (x1x+xnx)+...+(x2x+xn1x) (1)
由绝对值不等式有:
∣ x n − x 1 ∣ + . . . + ∣ x n − 1 − x 2 ∣   ( 2 ) |x_n-x_1|+...+|x_{n-1}-x_2|\ (2) xnx1+...+xn1x2 (2)
(2)式为(1)式的最小值

image.png
要让等号成立,就要让x在两数之间
若n为奇数,那么x等于中位数。若n为偶数,那么x在中间两个数(包含两个数)之间就行

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

const int N = 1e5 + 10;
int a[N];

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++ i ) scanf("%d", &a[i]);
    sort(a, a + n);
    int res = 0;
    for (int i = 0; i < n; ++ i ) res += abs(a[i] - a[n / 2]);
    printf("%d\n", res);
    return 0;
}

推公式

125. 耍杂技的牛

125. 耍杂技的牛 - AcWing题库
image.png

( w i + s i ) (w_i + s_i) (wi+si)为关键字进行升序排序,以从小到大的顺序从上到下摆放奶牛,此时的最大危险系数一定是所有摆放中最小的

证明:假设存在若 ( w i + s i ) > ( w i + 1 + s i + 1 ) (w_i + s_i) > (w_{i+1} + s_{i+1}) (wi+si)>(wi+1+si+1),风险系数是所有摆放中最小的
我们可以计算交换两头奶牛前后,第i个与第i+1个位置上的危险系数
交换前:
第i个位置的危险系数: ( w 1 + w 2 + . . . + w i − 1 − s i ) (w_1+w_2+...+w_{i-1}-s_i) (w1+w2+...+wi1si)
第i+1个位置的危险系数: ( w 1 + w 2 + . . . + w i − s i + 1 ) (w_1+w_2+...+w_i-s_{i+1}) (w1+w2+...+wisi+1)
交换后:
第i个位置的危险系数: ( w 1 + w 2 + . . . + w i − 1 − s i + 1 ) (w_1+w_2+...+w_{i-1}-s_{i+1}) (w1+w2+...+wi1si+1)
第i+1个位置的危险系数: ( w 1 + w 2 + . . . + w i − 1 + w i + 1 − s i ) (w_1+w_2+...+w_{i-1}+w_{i+1}-s_i) (w1+w2+...+wi1+wi+1si)
减去这四个式子中相同项: ( w 1 + w 2 + . . . + w i − 1 ) (w_1+w_2+...+w_{i-1}) (w1+w2+...+wi1)

交换前:
第i个位置的危险系数: ( − s i ) (-s_i) (si)
第i+1个位置的危险系数: ( w i − s i + 1 ) (w_i-s_{i+1}) (wisi+1)
交换后:
第i个位置的危险系数: ( − s i + 1 ) (-s_{i+1}) (si+1)
第i+1个位置的危险系数: ( w i + 1 − s i ) (w_{i+1}-s_i) (wi+1si)
再加上: ( s i + s i + 1 ) (s_i+s_{i+1}) (si+si+1)

交换前:
第i个位置的危险系数: ( s i + 1 ) (s_{i+1}) (si+1)
第i+1个位置的危险系数: ( w i + s i )   ( 2 ) (w_i+s_{i})\ (2) (wi+si) (2)
交换后:
第i个位置的危险系数: ( s i )   ( 3 ) (s_{i})\ (3) (si) (3)
第i+1个位置的危险系数: ( w i + 1 + s i + 1 ) (w_{i+1}+s_{i+1}) (wi+1+si+1)

已知: ( w i + s i ) > ( w i + 1 + s i + 1 ) (w_i + s_i) > (w_{i+1} + s_{i+1}) (wi+si)>(wi+1+si+1),观察(2)式与(3)式,我们能得到 ( w i + s i ) > m a x ( w i + 1 + s i + 1 , s i ) (w_i + s_i) > max(w_{i+1}+s_{i+1}, s_i) (wi+si)>max(wi+1+si+1,si)
同时 ( w i + s i ) > w i + 1 + s i + 1 > s i + 1 (w_i + s_i) > w_{i+1}+s_{i+1} > s_{i+1} (wi+si)>wi+1+si+1>si+1,所以交换前第i个位置与第i+1个位置的较大值为 ( w i + s i ) (w_i + s_i) (wi+si)
但是交换后第i个位置与第i+1个位置的较大值小于 ( w i + s i ) (w_i + s_i) (wi+si),也就是交换前第i个位置与第i+1个位置的较大值
即,交换过后危险系数变小了,与前提矛盾,所以摆放奶牛的序列中,不能存在 ( w i + s i ) > ( w i + 1 + s i + 1 ) (w_i + s_i) > (w_{i+1} + s_{i+1}) (wi+si)>(wi+1+si+1),即所有奶牛的 ( w + s ) (w+s) (w+s)需要从小到大地从上往下摆放,才能得到所有摆放中最小的最大危险系数

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

const int N = 1e5 + 10;
struct cow
{
    int s, w;
    bool operator<(const cow& x)
    {
        return (s + w) < (x.s + x.w);
    }
}cows[N];

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++ i ) scanf("%d%d", &cows[i].w, &cows[i].s);
    sort(cows, cows + n);
    
    int res = -2e9, sum = 0;
    for (int i = 0; i < n; ++ i ) 
    {
        res = max(res, sum - cows[i].s);
        sum += cows[i].w;
    }
    printf("%d\n", res);
    return 0;
}

debug:res要设置为-2e9,因为第一头牛的危险系数可能最小且为负数,这时res就要设置成一个比它还小的数

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

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

相关文章

Vue3项目(vben框架)打包时报错:JavaScript heap out of memory

我用的方法二 方法三解决了问题&#xff0c;方法二中将内存设置为了16g&#xff0c;方法三中内存设置16g也就是LIMIT16384 异常 FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory 原因 JavaScript 内存不足&#xff0c;指的就是Node,N…

Python爬虫学习笔记(十三)————CrawlSpider

目录 1.CrawlSpider介绍 2.使用方法 &#xff08;1&#xff09;提取链接 &#xff08;2&#xff09;模拟使用 &#xff08;3&#xff09;提取连接 &#xff08;4&#xff09;注意事项 3.运行原理 4.Mysql 5.pymysql的使用步骤 6.数据入库 &#xff08;1&#xff09;s…

uniapp使用

scroll-view封装tab组件 一个灵活的组件&#xff0c;可以自定义配置&#xff0c;&#xff0c;会设置一个 defaultConfig 去接收父组件传递的值去设置样式&#xff1a;比如 文字的颜色&#xff0c;激活文字的颜色&#xff0c;滑块的颜色&#xff0c;宽度&#xff0c;等滑块会跟着…

学习day51

几个注意点&#xff1a; 1.关于组件名&#xff1a; 一个单词组成&#xff1a; 第一种写法&#xff08;首字母小写&#xff09;&#xff1a;school 第二种写法&#xff08;首字母大写&#xff09;&#xff1a;School 多个单词组陈&#xff1a; 第一种写法&#xff08;kebab-case…

基础算法(三)

目录 一、双指针算法 二、位运算 三、区间合并 一、双指针算法 双指针算法模板: for(int i 0,j 0;i < n;i) {while(j < i && check(i,j)) j;//每道题的具体逻辑 } 1.1两个指针指向两个队列1.2两个指针指向一个队列 案例习题: 分割字符串 #include<…

【C语言】自定义类型:结构体,枚举,联合

目录 前言&#xff1a;一.结构体1.结构体的声明2.结构体特殊的声明3.结构体的自引用4.结构体变量的定义和初始化5.结构体内存对齐6.修改默认对齐数7.结构体传参 二.位段1.什么是位段2.位段的内存分配 三.枚举1.枚举的定义2.枚举的优点 四.联合&#xff08;共用体&#xff09;1.…

php使用PDO_sqlsrv

php拓展下载&#xff1a;Microsoft Drivers for PHP 发行说明 - PHP drivers for SQL Server | Microsoft Learn 参考文章&#xff1a;php7.3.4 pdo方式连接sqlserver 设置方法_pdo sqlserver_黑贝是条狗的博客-CSDN博客 php5.6.9安装sqlsrv扩展&#xff08;windows&#xff0…

BEVDet 论文解读

BEVDet: High-Performance Multi-Camera 3D Object Detection in Bird-Eye-View 作者单位 PhiGent Robotics 目的 2D 的视觉感知在过去的几年里有了急速的发展&#xff0c;涌现出一些优秀的范式工作&#xff0c;这些工作有较高的性能&#xff0c;可扩展性&#xff0c;以及多…

【前端设计】使用Verdi查看波形时鼠标遮住了parameter值怎么整

盆友&#xff0c;你们在使用Verdi的时候&#xff0c;有没有遇到过鼠标遮挡着了parameter数值的场景&#xff1f;就跟下面这个示意图一样&#xff1a; 最可恨的是这个参数值他会跟着你的鼠标走&#xff0c;你想把鼠标移开看看看这个例化值到底是多大吧&#xff0c;这个数他跟着你…

云原生基础设施实践:NebulaGraph 的 KubeBlocks 集成故事

像是 NebulaGraph 这类基础设施上云&#xff0c;通用的方法一般是将线下物理机替换成云端的虚拟资源&#xff0c;依托各大云服务厂商实现“服务上云”。但还有一种选择&#xff0c;就是依托云数据基础设施&#xff0c;将数据库产品变成为云生态的一环&#xff0c;不只是提供自身…

直播回顾 | SDS 容灾方案,让制品数据更安全

7 月 18 日&#xff0c;腾讯云 CODING 与 XSKY星辰天合联合举办了主题为“SDS 容灾方案&#xff0c;让制品数据更安全”的线上研讨会。 来自腾讯云 CODING 的高级解决方案架构师陈钧桐和 XSKY星辰天合金融行业解决方案专家战策&#xff0c;分享了制品管理的困境与需求、腾讯云…

【数据挖掘】如何修复时序分析缺少的日期

一、说明 我撰写本文的目的是通过引导您完成一个示例来帮助您了解 TVF 以及如何使用它们&#xff0c;该示例解决了时间序列分析中常见的缺失日期问题。 我们将介绍&#xff1a; 如何生成日期以填补数据中缺失的空白如何创建 TVF 和参数的使用如何呼叫 TVF我们将考虑扩展我们的日…

Less知识点整理学习笔记

文章目录 1. Less介绍2. 安装2.1 部署node.js环境2.2 安装Less2.3 WebStorm配置Less 3. Less语法3.1 变量3.2 嵌套3.3 运算 1. Less介绍 Less是CSS预处理语言&#xff0c;可以使用变量、嵌套、运算等&#xff0c;便于维护项目CSS样式代码。 2. 安装 2.1 部署node.js环境 官…

Python爬虫学习笔记(十二)————scrapy案例

目录 1.yield 2.案例&#xff1a;当当网 3.案例&#xff1a;电影天堂 1.yield &#xff08;1&#xff09;带有 yield 的函数不再是一个普通函数&#xff0c;而是一个生成器generator&#xff0c;可用于迭代 &#xff08;2&#xff09; yield 是一个类似 return 的关键字&am…

《数据分析-JiMuReport07》JiMuReport报表开发-下拉框条数参数调整

JimuReport报表下拉框条数参数调整 {selectSearchPageSize:n} 1.下拉框条数限制 下拉框默认只显示10条记录&#xff0c;如果想要显示更多条数可以通过添加参数实现。 2.参数 selectSearchPageSize参数&#xff0c;设置参数大小 3.效果 可以看到设置的下拉框条数20条已经实现

细说小程序底部标签---【浅入深出系列006】

浅入深出系列总目录在000集 如何0元学微信小程序–【浅入深出系列000】 文章目录 本系列校训学习资源的选择 学习语法的前提底部标签的总概鹅厂的自定义标签官方说明&#xff1a; 先来了解app.json文件tabBar 位于app.json哪里 使用流程要注意的是&#xff1a;配套资源作业&a…

el-popover在原生table中,弹出多个以及内部取消按钮无效问题

问题&#xff1a;当el-popover和原生table同时使用的时候会失效&#xff08;不是el-table) <el-popover placement"bottom" width"500" trigger"click" :key"popover-${item.id}"></el-popover> 解决&#xff1a; :key…

虚拟数字人——NeRF实现实时对话数字人

前言 1.这是一个能实时对话的虚拟数字人demo,使用的是NeRF&#xff08;Neural Radiance Fields&#xff09;&#xff0c;训练方式可以看看我前面的博客。 2.文本转语音是用了VITS语音合成&#xff0c;项目git:https://github.com/jaywalnut310/vits . 3.语言模型是用了新开…

Jenkins从配置到实战(一) - 实现C/C++项目自动化编译

前言 本文章主要介绍了&#xff0c;如何去安装和部署Jenkins&#xff0c;并实现自动拉取项目代码&#xff0c;自动化编译流程。 网站 官网中文网站 下载安装 可以下载这个 安装jenkins前先安装java yum search java|grep jdkyum install java-1.8.0-openjdk 安装jenkins j…

NE555 PWM输出

NE555是一种集成电路&#xff08;IC&#xff09;&#xff0c;通常用于电子电路的各种目的&#xff0c;包括计时器、振荡器等等。 本文介绍搭建NE555电路输出PWM信号&#xff0c;电路如图下&#xff1a; 使用该电路可以输出PWM占空比≥50%波形&#xff0c;仿真波形如下图&#…