原题
题目描述:
我们定义一个整数区间[a,b]:是一个从a开始至b 结束的连续整数的集合。编一个程序,对给定的 n(n≤1000 )个区间,找出满足下述条件的所含元素个数最少的集合中元素的个数:对于所给定的每一个区间,都至少有两个不同的整数属于该集合。
输入格式:
第一行一个正整数n,接下来有n行,每行给定一个区间的a,b值。
输出格式:
一个正整数,满足条件的集合所包含的最少元素个数。
样例输入:
4 3 6 2 4 0 2 4 7
样例输出:
4
思路分析
读题
乍一看,发现和洛谷的题很像,但看了看才发现这道题将“都至少有两个不同的整数属于该集合”改为了“都至少有两个不同的整数属于该集合”!
思考
贪心思路
这道题求的是两个点一个区间,那我们先在区间1放1个点在右端点,让更多的区间可以用到(和洛谷的版本的思路相同),如果当前这个区间还不够,那就在当前的线段中选一个点来求。
比如有三个线段
正确答案只要4个点就行了,如图中青蓝的点:
我们为了让点的利用率更高,我们需要分类讨论
- 这个区间还差2个点,放2个节点分别在右端点和右端点-1的位置,将利用到了这些位置的区间节点需求减少利用到的节点个数。
- 这个区间还差1个点,放1个节点在右端点位置,将利用到了这个位置的区间节点需求减少一个。
- 这个区间点够了,不需要再添加点,直接跳过
验证贪心策略
当区间按上图排序时,正确答案应当是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();
}