区间合并算法

总说

本篇文章可能写的有点潦草(时间有点紧),仅供个人参考与复习,如有错误欢迎指出。

一、区间合并介绍

思路

常见类型是给我们n个区间,每个区间都符合性质,区间之间可能有交集,我们有时需要把相交区间合并,方便后续统计和计算。

题目链接:P1496 火烧赤壁 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

本题就是给了n个区间,让你统计总着火长度,由于总距离给的很大,如10^9,我们不能直接开一个数组,这里也用到了一些离散化的知识,把每个区间存下来,按左端点从小到大排序。由于区间之间可能有重复,所以想到了区间合并,合并时候每两个区间之间不会相交,之间遍历所有区间然后把区间长度相加即可。

代码模板

#include<iostream>
#include<cstring>
#include<algorithm>

#define x first //左边界 
#define y second //右边界 

using namespace std;

const int N = 2e4 + 10;
const int INF = 0x3f3f3f3f;

typedef long long ll;
typedef pair<int, int> PII;

int n;
PII a[N]; //定义一个pair类型数组,记录左右边界 

int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
		scanf("%d %d", &a[i].x, &a[i].y);
	
	sort(a + 1, a + n + 1); //区间合并前要先按左端点从小到大排序
	
	int l = -INF, r = -INF; //初始左右边界 
	ll res = 0; //记录答案 
	for(int i = 1; i <= n; i++)
	{
		if(a[i].x > r) //不相交
		{
			res += r - l;
			l = a[i].x;
			r = a[i].y;
		} 
		else
		{
			r = max(a[i].y, r);
			if(i == n) //如果是最后一个了 直接结算
				res += r - l; 
		}
	} 
	printf("%lld", res);
	return 0;
}

二、题目练习

2.1 记录合并区间

题目描述:

题目链接:P2434 [SDOI2005] 区间 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路分析:

基本上是板子题,这里需要在遍历的时候,如果此时2个区间不相交,就把上一个合并好的区间存起来。

代码模板:

#include<iostream>
#include<cstring>
#include<algorithm>

#define x first
#define y second

using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 5e4 + 10;

int n, cnt;
PII a[N], res[N];

int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
		scanf("%d %d", &a[i].x, &a[i].y);
	
	sort(a + 1, a + n + 1);
	
	int l = -1, r = -1;
	for(int i = 1; i <= n; i++)
	{
		if(a[i].x > r)
		{
			if(r != -1)
				res[++cnt] = {l, r}; //存下 
			l = a[i].x;
			r = a[i].y;
		}
		else
			r = max(r, a[i].y);
	}
	if(r != -1)
		res[++cnt] = {l, r};
	
	for(int i = 1; i <= cnt; i++)
		printf("%d %d\n", res[i].x, res[i].y);
	return 0;
}

2.2 合并过程更新最值

题目描述:

题目链接:1343. 挤牛奶 - AcWing题库

思路分析:

还是板子题,就是在合并过程中注意更新答案即可。

代码模板:

#include<iostream>
#include<cstring>
#include<algorithm>

#define x first
#define y second

using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 5e3 + 10;

int n, res1, res2;
PII a[N];

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%d %d", &a[i].x, &a[i].y);
        
    sort(a + 1, a + n + 1);
    int l = -1, r = -1;
    for(int i = 1; i <= n; i++)
    {
        res1 = max(res1, r - l); //单个区间
        if(a[i].x > r)
        {
            if(r != -1)
            {
                res1 = max(res1, a[i].y - a[i].x);//合并的区间
                res2 = max(res2, a[i].x - r);// 2个区间中间间隔
            }
            l = a[i].x;
            r = a[i].y;
        }
        else
            r = max(r, a[i].y);
    }
    printf("%d %d", max(res1, r - l), res2);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值