区间贪心

news/2024/7/11 4:01:05 标签: 算法, 贪心

区间贪心做法还是比较单一的,一共三种情况
左端点排序、右端点排序,多关键字排序

区间选点

按右端点排序,在每一段区间中靠右边的点是最优的,因为越靠右边的点就越有可能覆盖更多的区间

证明过程可以用夹逼定理进行证明,假定最终的最小值是ans,统计出来的数量是num,证明ans>=num且ans<=num,就可以证明ans==num

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct sa
{
    int l;
    int r;
}range[N];
int cmp(const sa &a,const sa &b)
{
    return a.r<b.r;
}
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++) scanf("%d%d",&range[i].l,&range[i].r);
    sort(range,range+n,cmp);
    int res=0,ed=-(1e9+10);
    for(int i=0;i<n;i++)
    {
        if(range[i].l>ed)
        {
            res++;
            ed=range[i].r;
        }
    }
    cout<<res<<endl;
    return 0;
}

最大不相交区间数量

和这道题一样的模型之前遇到过几个,比如:一个人要去看表演,每个给出每个表演的时间,问怎么能看到最多的节目

这道题和上道题是完全一样的!代码也是一样的!

区间分组

先按左端点从小到大排序
对于每一组,如果所有组一组最右边的右端点大于当前区间的左端点,那么说明有交集,需要重新建立一个组
这里用小根堆维护每一组最右边的右端点,每次取出最小的最右端点,如果最小的最右端点都无法插入,那么说明整个堆中的最有端点都不行。如果可以划分成一组,那么就只需要更新当前区间的最右端点值即可

证明过程同样可以用夹逼定理进行证明,假定最终的最小值是ans,统计出来的数量是num,证明ans>=num且ans<=num,就可以证明ans==num

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct sa
{
	int l,r;
}range[N];
int cmp(const sa &a,const sa &b)
{
	return a.l<b.l;
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++) scanf("%d%d",&range[i].l,&range[i].r);
	sort(range,range+n,cmp);
	priority_queue<int,vector<int>,greater<int> >vis;
	for(int i=0;i<n;i++)
	{
		if(vis.empty()||vis.top()>=range[i].l) vis.push(range[i].r);
		else 
		{
			int t=vis.top();
			vis.pop();
			vis.push(range[i].r);
		}
	}
	cout<<vis.size()<<endl;
	return 0;
}

区间覆盖

先按左端点从小到达大排序
每一次选取能覆盖掉st的右端点最靠右的区间,然后将st更新成右端点,循环得到解
如果当前没有区间能覆盖到st,则无解
如果循环到最后没能覆盖掉en,则无解

对于这个做法的证明可以直接证答案
对于答案都可以通过这个
算法在区间数目不发生变化的情况下转化成算法可以算出的答案
这样算法的正确性就得到了证明

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct sa
{
	int l,r;
}range[N];
int cmp(const sa &a,const sa &b)
{
	return a.l<b.l;
}
int main()
{
	int st,en;
	cin>>st>>en;
	int n;
	cin>>n;
	for(int i=0;i<n;i++) scanf("%d%d",&range[i].l,&range[i].r);
	sort(range,range+n,cmp);
	int res=0;
	for(int i=0;i<n;i++)
	{
		int j=i,r=-(1e9+10);
		while(j<n&&range[j].l<=st)
		{
			r=max(r,range[j].r);
			j++;
		}
		if(r<st)
		{
			cout<<"-1"<<endl;
			return 0;
		}
		res++;
		if(r>=en)
		{
			cout<<res<<endl;
			return 0;
		}
		st=r;
		i=j-1;
	}
	cout<<"-1"<<endl;
	return 0;
}

http://www.niftyadmin.cn/n/815756.html

相关文章

group by的使用

group by的使用 环境&#xff1a;win8.1 mysql5.7 “group by”就是根据“by”指定的规则对数据进行分组&#xff0c;所谓的分组就是将一个“数据集”划分成若干个“小区域”&#xff0c;然后针对若干个“小区域”进行数据处理。 原始表&#xff1a; 简单的group by 示例1 …

Huffman树——合并果子

原题链接 解析 这道题是一个典型的Huffman树的题目 对于任何一种构造都可以转化成一棵树&#xff0c;这道题相当于是求跟结点的权制最小 因此这道题可以用Huffman树来进行解决&#xff0c;权值越小的点离树根越远越好&#xff0c;权值越大的点离树根越近越好 因此可以用小根堆…

排队打水

原题链接 结论&#xff1a;时间短的小朋友先打水&#xff0c;时间长的小朋友后打水 证明&#xff1a;我们假设最终的答案中有逆序&#xff0c;如果将逆序倒过来&#xff0c;那么一定可以得到一个更小的答案 代码 #include <bits/stdc.h> using namespace std; typedef…

耍杂技的牛

原题链接 结论&#xff1a;按照牛的体重和强壮值之和从小到大排序得到的序列是危险值的最大值最小的排列方式 证明&#xff1a;这道题我们可以用转换的思路来证明&#xff0c;即&#xff1a;如果存在最终答案的序列中存在逆序的情况&#xff0c;我们一定一刻通过把逆序倒过来的…

牛客题单——贪心、数论

题单链接 反素数 反素数就是一个数的因子大于所有小于这个数因子的数 题目中要求的区间内的最大反素数 等价于 求这个区间内因子最多的数且这个数最小 可以用反证法进行证明&#xff1a; 假设在当前区间中的答案是x&#xff0c;如果y的约数个数大于x&#xff0c;那么x就不是…

翻硬币

问题 J: 翻硬币 时间限制: 1 Sec 内存限制: 128 MB提交: 19 解决: 3[提交] [状态] [讨论版] [命题人:外部导入]题目描述 小明正在玩一个“翻硬币”的游戏。桌上放着排成一排的若干硬币。我们用 * 表示正面&#xff0c;用 o 表示反面&#xff08;是小写字母&#xff0c;不是零…

浏览器上网流程以及套接字介绍

1.输入网址 2.DNS解析 3.TCP连接 4.客户端发送请求 5.服务端根据请求返回响应 6.浏览器根据返回的html、css、js和图片渲染页面 二、套接字 应用层通过传输层进行数据通信时&#xff0c;TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程…

MyBatis从入门到精通:第一章数据库创建文件

/*创建数据库mybatis&#xff0c;并指定编码方式为utf8&#xff0c;字符比较规则为utf8_general_ci*/ CREATE DATABASE mybatis DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;/*创建表*/ CREATE TABLE country(id INT NOT NULL AUTO_INCREMENT,countryname VARCHAR(255…