当前位置: 首页 > wzjs >正文

免费企业建网站广州网站建设推荐q479185700霸屏

免费企业建网站,广州网站建设推荐q479185700霸屏,网站建设 计入哪个科目,大连连城传媒数据结构与算法学习笔记----贪心区间问题 author: 明月清了个风 first publish time: 2025.4.3 ps⭐️一个月没更了,三月初出去玩了,然后大论文写到现在哈哈哈 贪心问题其实不像其他问题能够有非常具体的解决思路,往往是通过尝试找到一种方…

数据结构与算法学习笔记----贪心区间问题

@@ author: 明月清了个风
@@ first publish time: 2025.4.3

ps⭐️一个月没更了,三月初出去玩了,然后大论文写到现在哈哈哈

贪心问题其实不像其他问题能够有非常具体的解决思路,往往是通过尝试找到一种方法后再证明其正确性,贪心的关键在于关注最优子结构向最优全局解的证明。

Acwing 905. 区间选点

[原题链接](905. 区间选点 - AcWing题库)

给定 N N N个闭区间 [ a i , b i ] [a_i, b_i] [ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。

输出选择的点的最小数量。

位于区间端点上的点也算作区间内。

输入格式

第一行包含整数 N N N,表示区间数。

接下来 N N N行,每行包含两个整数 a i , b i a_i, b_i ai,bi,表示一个区间的两个端点。

输出格式

输出一个整数,表示所需的点的最小数量。

数据范围

1 ≤ N ≤ 1 0 5 1 \le N \le 10^5 1N105

− 1 0 9 ≤ a i ≤ b i ≤ 1 0 9 -10^9 \le a_i \le b_i \le 10^9 109aibi109

思路

这里先直接给出结论:

  1. 将所有区间按右端点从小到大排序。
  2. 从前往后依次枚举每个区间,如果当前区间中已经包含点,则不选择;若不包含点,则选择当前区间的右端点。

接下来证明此策略的正确性:

因为我们要选择尽可能少的点,因此目标也就是使选择的每个点覆盖尽可能多的区间

  • 首先进行贪心选择的正确性证明,也就是为什么选择右端点?

    对于第一个区间 [ a 1 , b 1 ] [a_1,b_1] [a1,b1]来说,其右端点 b 1 b_1 b1经过排序后为所有区间的右端点中的最小值,那么剩余区间就只有两种情况,一是与 [ a 1 , b 1 ] [a_1,b_1] [a1,b1]有交集,也就是 a i < b 1 a_i < b_1 ai<b1;二是与 [ a 1 , b 1 ] [a_1,b_1] [a1,b1]无交集,也就是 a i > b 1 a_i > b_1 ai>b1。那么对于第一种情况,当我们选择了右端点 b 1 b_1 b1后,该区间一定包含 b 1 b_1 b1,所以不用选择点;对于第二种情况,该区间不包含 b 1 b_1 b1,一定会另选点。也就是说,当我们选择了第一个区间的右端点 b 1 b_1 b1后,我们就覆盖了所有左端点 a i < b 1 a_i < b_1 ai<b1的区间,并且我们选择了是在排序后最靠前的 b 1 b_1 b1,也意味着为后续区间留下了更大的右端点空间。

    由第一个区间进行推广,假设前 k k k个点的选择都是像上面的局部最优解,那么对于第 k + 1 k + 1 k+1个点,我们选择的一定是未被覆盖的区间中的右端点最小的点,与上面的选择一致,因此正确。

  • 然后证明全局的最优性:

    也就是假设存在一个最优解,其选择的点数 m ′ m' m小于根据上面的选法选出的点数 m m m,证明这是不可能的。

    根据我们的选择方案,我们选择的每个点所在的区间一定是没有交集的,因为当我们选择一个点后,下一个区间的左端点如果小于该点,则一定不会被选择,若被选择,一定是因为该区间的左端点大于了上一个选择的点,也就意味着覆盖所有的区间至少需要 m m m个点,因此不存在更优解。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 100010;int n;
struct Range
{int l, r;bool operator < (const Range &W)const{return r < W.r;}
}range[N];int main()
{cin >> n;for(int i = 0; i < n; i ++){int l, r;cin >> l >> r;range[i] = {l, r};}sort(range, range + n);int res = 0, ed = -2e9;for(int i = 0; i < n; i++){if(range[i].l > ed){res ++;ed = range[i].r;}}cout << res << endl;return 0;
}

Acwing 908. 最大不相交区间数量

[原题链接](908. 最大不相交区间数量 - AcWing题库)

给定 N N N个闭区间 [ a i , b i ] [a_i, b_i] [ai,bi],请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。

输出可选取区间的最大数量。

输入格式

第一行包含整数 N N N,表示区间数。

接下来 N N N行,每行包含两个整数 a i , b i a_i, b_i ai,bi,表示一个区间的两个端点。

输出格式

输出一个整数,表示可选取区间的最大数量。

数据范围

1 ≤ N ≤ 1 0 5 1 \le N \le 10^5 1N105

− 1 0 9 ≤ a i ≤ b i ≤ 1 0 9 -10^9 \le a_i \le b_i \le 10^9 109aibi109

思路

直接说结论吧这一题,做法和上一题完全一致,回顾一下上一题的思路其实也能看出来。

同样可以从两个方向来证明,

根据上一题选法,选择的相邻的两个点一定是没有交集的两个区间的点,因此就可以认为我们的答案 a n s ans ans一定是一种可行方案,且 a n s ≥ c n t ans \ge cnt anscnt

下一步证明 a n s ≤ c n t ans \le cnt anscnt,这里可以用反证法,假设我们的答案 a n s ans ans是大于 c n t cnt cnt的,也就意味着可以选择更多的存在于没有交集的区间的点,但是根据我们的选法来看,该选法覆盖了所有的区间,不存在额外的区间中的点,因此得证。

代码和上一题一样。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 100010;int n;
struct Range
{int l, r;bool operator < (const Range &W)const{return r < W.r;}
}range[N];int main()
{cin >> n;for(int i = 0; i < n; i ++){int l, r;cin >> l >> r;range[i] = {l, r};}sort(range, range + n);int res = 0, ed = -2e9;for(int i = 0; i < n; i++){if(range[i].l > ed){res ++;ed = range[i].r;}}cout << res << endl;return 0;
}

Acwing 906. 区间分组

[原题链接](906. 区间分组 - AcWing题库)

给定 N N N个闭区间 [ a i , b i ] [a_i, b_i] [ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。

输出最小组数。

输入格式

第一行包含整数 N N N,表示区间数。

接下来 N N N行,每行包含两个整数 a i , b i a_i, b_i ai,bi,表示一个区间的两个端点。

输出格式

输出一个整数,表示最小组数。

数据范围

1 ≤ N ≤ 1 0 5 1 \le N \le 10^5 1N105

− 1 0 9 ≤ a i ≤ b i ≤ 1 0 9 -10^9 \le a_i \le b_i \le 10^9 109aibi109

思路

同样直接给出思路,因为是经典的模型。

  1. 将所有区间按左端点从小到大排序
  2. 从前往后处理每个区间,判断能否放在某个组里,也就是判断当前区间的左端点是否大于该组中的最大的右端点
  3. 如果上一步中未能找到一个组,那么就开一个新的组。

下一步就是证明该做法的正确性,首先证明我们的算法得到的 c n t cnt cnt是否大于等于正确答案 a n s ans ans,因为选取的规则保证了能够按照题意得到结果,因此肯定是一种合法方案,因此 c n t ≥ a n s cnt \ge ans cntans肯定成立

而对于 c n t ≤ a n s cnt \le ans cntans可以从特殊时间节点来看,也就是创建第 c n t cnt cnt个组的时刻,当我们新开第 c n t cnt cnt个组时,根据选法来看,保证了前 c n t − 1 cnt - 1 cnt1个组的最大右端点值一定大于当前这个区间的右端点,因此无法放入任何一个组,进而新开了第 c n t cnt cnt个组,这也意味着这 c n t cnt cnt个组的第一个区间一定是相互之间有交集的,也就是新开到第 c n t cnt cnt个组的这个区间的左端点一定被包含在了前 c n t cnt cnt个组里,因此得证。

还有一个问题就是,如果存在多个能够放入的组应该放在哪一个,会不会影响最终的结果,答案是不会,任取一个就行,体现在代码中就是选最小的组。这个问题的核心就是存在多个可用组的情况下,为什么选择任意一个得到的答案都是最小的,这是因为答案其实就是所有区间的最大重叠数,也就是最多的存在同一点的区间数。假设这个数是 k k k,那么说明有 k k k个区间存在相交点,那么就至少需要 k k k组才能容纳这 k k k个组,而剩余区间的重叠数一定小于等于 k k k,因此可以分别分到这 k k k个组中。

代码

#include <iostream>
#include <algorithm>
#include <queue>using namespace std;const int N = 100010;int n;
struct Range
{int l, r;bool operator< (const Range &W)const{return l < W.l;}
}range[N];int main()
{scanf("%d", &n);for(int i = 0; i < n; i ++){int l, r;cin >> l >> r;range[i] = {l, r};}sort(range, range + n);priority_queue<int, vector<int>, greater<int>> heap;for(int i = 0; i < n; i ++){auto r = range[i];if(heap.empty() || heap.top() >= r.l) heap.push(r.r);else{int t = heap.top();heap.pop();heap.push(r.r);}}printf("%d\n", heap.size());return 0;
}

Acwing 907. 区间覆盖

[原题链接](907. 区间覆盖 - AcWing题库)

给定 N N N个闭区间 [ a i , b i ] [a_i, b_i] [ai,bi]以及一个区间 [ s , t ] [s,t] [s,t],请你选择尽量少的区间,将指定区间完全覆盖。

输出最少区间数,如果无法完全覆盖则输出 − 1 -1 1

输入格式

第一行包含两个整数 s s s t t t,表示给定区间的两个端点。

第二行包含整数 N N N,表示给定区间数。

接下来 N N N行,每行包含两个整数 a i , b i a_i, b_i ai,bi,表示一个区间的两个端点。

输出格式

输出一个整数,表示所需最少区间数。

如果无解,则输出 − 1 -1 1

数据范围

1 ≤ N ≤ 1 0 5 1 \le N \le 10^5 1N105

− 1 0 9 ≤ a i ≤ b i ≤ 1 0 9 -10^9 \le a_i \le b_i \le 10^9 109aibi109

− 1 0 9 ≤ s ≤ t ≤ 1 0 9 -10^9 \le s \le t \le 10^9 109st109

思路

同样地给出思路:

  1. 将所有区间按左端点从小到大排序
  2. 从前往后枚举每个区间,在所有能覆盖 s t st st的区间中选择右端点最大的区间,然后将 s t st st更新为这个值

这个思路很容易证明是正确的,首先选法一定是合法的,并且保证了每一步的覆盖范围最大,且当前步骤的选取不会影响后续的选择,因为已经排过序了。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 100010;int n;
struct Range
{int l, r;bool operator< (const Range &W)const {return l < W.l;}
}range[N];int main()
{int st, ed;scanf("%d%d", &st, &ed);scanf("%d", &n);for(int i = 0; i < n; i ++){int l,r ;cin >> l >> r;range[i] = {l, r};}sort(range, range + n);int res = 0;bool success = false;for(int i = 0; i < n; i ++){int j = i, r = -2e9;while(j < n && range[j].l <= st){r = max(r, range[j].r);j ++;}if(r < st){res = -1;break;}res ++;if(r >= ed){success = true;break;}st = r;i = j - 1;}if(!success) res = -1;cout << res << endl;return 0;}

文章转载自:

http://KxnKStiK.tpLht.cn
http://HGddId1V.tpLht.cn
http://aAfj26eK.tpLht.cn
http://vjKf4uwq.tpLht.cn
http://IZnPefZK.tpLht.cn
http://DM09qWHq.tpLht.cn
http://INxn3kXQ.tpLht.cn
http://AUVbFmxw.tpLht.cn
http://vNPiHnvd.tpLht.cn
http://4njmtFEf.tpLht.cn
http://wX1KIW2W.tpLht.cn
http://oLvNQkwp.tpLht.cn
http://Lg3FoIqh.tpLht.cn
http://sjRW6LCM.tpLht.cn
http://7eUPNNHg.tpLht.cn
http://AyYshhKA.tpLht.cn
http://IS48OdFe.tpLht.cn
http://AaYZWWNZ.tpLht.cn
http://4b5O9MWg.tpLht.cn
http://Cycp43nw.tpLht.cn
http://WpySDaqx.tpLht.cn
http://DPe3NtSA.tpLht.cn
http://HeZAn8cl.tpLht.cn
http://vw0cF2jm.tpLht.cn
http://CiVkCtPF.tpLht.cn
http://cgsvlWDO.tpLht.cn
http://X8AoyGkC.tpLht.cn
http://A0aucfBq.tpLht.cn
http://hzKKPJyW.tpLht.cn
http://SgymHkd2.tpLht.cn
http://www.dtcms.com/wzjs/779686.html

相关文章:

  • 做网站有那几种末班中国纪检监察报电子报刊
  • 手机做网站价格类似稿定设计的网站
  • 汕头网站设计电话暴雪安全令
  • 网站搭建要多少钱网络营销的培训课程
  • 襄阳网站建设-飞鱼网络手机制作网页app
  • phpmysql网站设计买卖交易网
  • 哪里有免费的网站推广全世界足球排名国家
  • 做网站是要收费的吗网络热词2023
  • 网站建设公司做ppt吗西安网站排名优化
  • 导航网站设计网站权限控制
  • 能不能同行网站做站长统计专业企业网站建设报价
  • 广西响应式网站制作进入百度一下官网
  • 专业设计网站推荐常州做网站公司有哪些
  • 接做网站需要问什么条件做58同城的网站要多少钱
  • 知己知彼网站做网站语言排名2018
  • 周口公司做网站做网站的励志故事
  • 深圳最好的营销网站建设公司排名网站里的动画是什么软件做的
  • 合肥网站建站报广告代理唐山网站建设维护
  • 建筑工程素材资源网站电子商务平台内的自然人经营者
  • dedecms做的系统网站主页是哪一个文件门户网站架构
  • 南昌外包建站Wordpress用七牛云存储
  • 网站广告位外链建设对网站的影响
  • 宁波找网站建设企业微信开发者工具教程实例
  • 网站到期请续费泉州服装电商网站建设
  • 深圳专业软件网站建设seo的内容怎么优化
  • 建设网站找谁大气网站首页
  • 国内医院网站开发现状wordpress采集公众号图片
  • 工艺品网站模板下载-古色古香科技小论文怎么写
  • qq空间钓鱼网站制作网站在建设是什么意思
  • 建设168网站wordpress+导入+媒体