#10007. 「一本通 1.1 练习 3」线段

版权声明:有女朋友的老江的博客,转载请告知老江 https://blog.csdn.net/qq_42367531/article/details/84317542

【题目描述】

数轴上有 n 条线段,选取其中 k 条线段使得这 k 条线段两两没有重合部分,问 k 最大为多少。

【输入格式】

第一行为一个正整数 n;

在接下来的 n 行中,每行有 2 个数 ai​,bi​,描述每条线段。

【输出格式】

输出一个整数,为 k 的最大值。

【样例输入】

3
0 2
2 4 
1 3

【样例输出】

2

【数据范围与提示】

对于 20% 的数据,n≤10;

对于 50% 的数据,n≤10^3;

对于 70% 的数据,n≤10^5;

对于 100% 的数据,n≤10^6, 0≤ai​<bi​≤10^6。

思路:第一眼看到这一题,我还是有种用dp的冲动,但是想了一下好像dp没有可以比较的东西,然后因为要求的是不重合的线段,而不是不重合的节数,那么直接贪心判断头尾是否重合就好了。首先,因为我们要判断头尾,而且为了混乱的话,我们要排序,而且要结构体排序,因为是两个数为一组,而且我们排序的是结尾,而不是开头,其次,排完序之后我们知道一定是循环找不相同的头尾,但是在寻找的时候一定要清楚,就算不找我们也会有一条线段不重复的,就是随便一条,所以记录答案的ans一定要为1,接着,我们要把排序后的最小的结尾定义为last,再接着,就是判断,然后判断之后,要把last更新为找到的这一条线段的结尾,在寻找其他的。这就是全部的思路,注意一个,不用快读和用来快读的时间相差了400多ms

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()//日常快读 
{
	char c=getchar();
	int x=0,f=1;
	while(c<48 || c>57)
	{
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>=48 && c<=57)
	{
		x=x*10+c-48;
		c=getchar();
	}
	return x*f;
}
struct node//定义日常结构体 
{
	int x,y;//x就是线段的开头 //y就是线段的结尾 
}a[1110000];
bool cmp(node n1,node n2)
{
	return n1.y<n2.y;//按照线段的结尾进行排序 
}
int main()
{
	int n; n=read();
	for(int i=1;i<=n;i++)
	{
		a[i].x=read();
		a[i].y=read();
	}
	sort(a+1,a+n+1,cmp);
	/*
		线段结尾的排序
		因为我们要求的是不重合的线段数,而不是结束
		所以只要结尾和开头不重合就是一条不重合的线段	
	*/ 
	int last=a[1].y;
	/*
		定义last为最小的线段结尾
		比如说:2 4
		        1 3
				4 7
		那么经过排序之后,这三条线段就会变成
		        1 3
				2 4
				4 7 
		虽然我们是按照线段的结尾来排序的,但是因为是结构体
		所以他的一整个都会进行排序,这就是结构体的好处
		所以通过例子我们可以知道,例子中的last值为3 
	*/ 
	int ans=1;
	/*
		ans是用来记录不重合的线段的 
		ans一定要定义为1
		因为我们要找的是不重合的线段
		所以必然会有一条是不重合的
		因为如果所有的线段都会重合的话
		那么任意一条线段都可以作为不重合的线段
		所以ans要定义为1,或者在输出的时候增加1 
	*/
	for(int i=2;i<=n;i++)
	/*
		这里是寻找出来除了原始的一条不重合之后
		还有没有可以组成不重合线段的线段 
		这里因为是寻找更多的不重合线段,所以ans要等于1
		然后还有一个就是,i从2开始是因为
		我们最开始的last是a[i].y
		说明我们这里就是要找其他的线段中有没有和最小的线段不重合的
		所以没有必要从1开始
		从2开始判断就好了 
	*/
	{
		if(a[i].x>=last)
		/*
			如果我们找到了一条线段的开头是大于或者等于 
			当前最小线段的结尾的话 
			说明这两条线段是完全不重合的
			那么我们就找到了第二条不重合的限度 
		*/
		{
			ans++;//不重合线段数增加1 
			last=a[i].y;
			/*
				把last更新为当前的这一条找到的线段的结尾
				还是老话,因为排序过,所以我们当前找到的这一条线段
				也是相对来讲小的,后面还有更大的
				然后继续寻找与当前线段不重合的线段 
			*/ 
		}
	}
	printf("%d\n",ans);
	return 0;
}

解释完毕,一点都不难,感觉我解释的太多了 

猜你喜欢

转载自blog.csdn.net/qq_42367531/article/details/84317542