WZOI-2529-整数区间-题解

原题

题目描述:

我们定义一个整数区间[a,b]:是一个从a开始至b 结束的连续整数的集合。编一个程序,对给定的 n(n≤1000 )个区间,找出满足下述条件的所含元素个数最少的集合中元素的个数:对于所给定的每一个区间,都至少有两个不同的整数属于该集合。

输入格式:

第一行一个正整数n,接下来有n行,每行给定一个区间的a,b值。

输出格式:

一个正整数,满足条件的集合所包含的最少元素个数。

样例输入:
4
3 6
2 4
0 2
4 7
样例输出:
4

思路分析

读题

乍一看,发现和洛谷的题很像,但看了看才发现这道题将“都至少有两个不同的整数属于该集合”改为了“都至少有两个不同的整数属于该集合”!

思考

贪心思路

这道题求的是两个点一个区间,那我们先在区间1放1个点在右端点,让更多的区间可以用到(和洛谷的版本的思路相同),如果当前这个区间还不够,那就在当前的线段中选一个点来求。

比如有三个线段

正确答案只要4个点就行了,如图中青蓝的点:

我们为了让点的利用率更高,我们需要分类讨论

  1. 这个区间还差2个点,放2个节点分别在右端点和右端点-1的位置,将利用到了这些位置的区间节点需求减少利用到的节点个数。
  2. 这个区间还差1个点,放1个节点在右端点位置,将利用到了这个位置的区间节点需求减少一个。
  3. 这个区间点够了,不需要再添加点,直接跳过
验证贪心策略

当区间按上图排序时,正确答案应当是4,如果我们不按推出的贪心策略搜索,可能会得到:

此时,用了5个节点,不是全局最优解,而按照上述的贪心策略可以通过局部最优解得到全局最优解。

再举个例子:

此时按照右端点排序后,找到的右端点放数,总计需要2个节点,与全局最优解相符。


AC代码(c++)

#include <bits/stdc++.h>
#pragma GCC optimize(1 , 2 , 3 , "Ofast" , "inline")
#define ll long long
using namespace std;
int n;
struct node{
	int x , y;
	int dot;//节点数量
}s[30005];

bool cmp(node x , node y)//按右端点排序
{
	return x.y < y.y;
}

void solve()
{
	scanf("%d" , &n);
	for (int i = 1 ; i <= n ; i++)
	{
		scanf("%d%d" , &s[i].x , &s[i].y);
		s[i].dot = 2;
	}
	sort (s + 1 , s + 1 + n , cmp);
	
	int len = 0;
	for (int i = 1 ; i <= n ; i++)//不失风度的暴力
	{
		if (s[i].dot == 2)//剩余点个数为2
		{
			len += 2;
			for (int j = i + 1 ;j <= n ; j++)
			{
				if (s[j].x == s[i].y) s[j].dot--;
				if (s[j].x < s[i].y)  s[j].dot -= 2;
			}
		}
		if (s[i].dot == 1)//剩余节点为1
		{
			len++;
			for (int j = i + 1 ; j <= n ; j++)
			{
				if (s[j].x <= s[i].y)
				{
					s[j].dot--;
				}
			}
		}
	}
	
	printf("%d" , len);
}

int main()
{
	solve();
}

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值