题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2037
Problem Description
“今年暑假不AC?”
“是的。”
“那你干什么呢?”
“看世界杯呀,笨蛋!”
“@#$%^&*%...”
确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。
作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)
Input
输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。
Output
对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。
Sample Input
12 1 3 3 4 0 7 3 8 15 19 15 20 10 15 8 18 6 12 5 10 4 14 2 9 0
Sample Output
5
题目分析:
1.这个是多组测试样例,所以把输入放循环条件里面,来达到这个效果。
2.每一个节目都有开始时间和结束时间,这个最关键的地方是对结束时间进行排序,然后遍历一遍,如果下一节目的开始时间大于等于这个节目的结束时间,下一个节目就符合要求,这样就能找到最多能看到多少个完整的节目,
下面解释为啥对结束时间排序能得到正确结果。
1.首先需要清楚一点,要想尽可能看多的节目,每个节目时间相对来说短一点比较好(不是绝对的),假设给你了一组数据,让你在演草纸上算,最多能看几个完整的节目,这样你试着来,肯定能找到答案。
2.比如你找到的答案是类似1-3,3-4,5-8,8-10这样的,结束时间的从小到大的,这一个而且下一个节目的开始时间肯定和上一个节目开始的时间差尽可能小一些。
3.对于给出的数据对结束时间进行排序后,这样不管是否相邻的两个节目是否都符合答案里的节目,但是这样能保证的是,如果这两个都符合要求,那看完这两个节目所花的时间肯定会少一些(可以慢慢想一想为什么,这一点很重要)。
4.这时候肯定有人会有疑问了,你对结束时间进行排序可以,那我对开始时间进行排序,排序之后如果下一个节目的开始时间大于等于当前节目的结束时间不可以吗?下面分析一下为啥这样不行,假如排序后出现了1-2,2-9,3-4,4-5,4-9这种情况,进行遍历时间就会选择1-2,2-9,但是这种情况并不是最好的选择方式。而如果选择结束时间进行排序,在进行排序后,选择靠前的的几个节目时间肯定不会长,因为这个节目的结束时间和上一个节目的结束在那控制着。
5.综上所述,还是选择对结束时间进行排序。
思路分析
每个节目的开始时间和结束时间是一对的,假如对结束时间进行排序,那开始时间肯定也要跟着走。如果要两个一维数组分别存每个节目的开始时间和结束时间,那如果对结束时间进行排序时,结束时间之间的顺序肯定会变,那开始时间的顺序就也要跟着变,这样不好控制,所以采用结构体用来存储每个节目的开始时间和结束时间。
结构体的优势:
假如定义一个结构体,在结构体里面定义两个整型变量e和s,然后用这种结构体定义一个数组a[100],就相当于数组的每一个项都包括两个整型数,比如数组a[0]里包括a[0].e和a[0].s(a[0]后加点再加结构体里相应的变量,就是调用结构体的变量的方法),而且这两个是绑定在一块的。这个绑定是结构体的优势所在,比如用结构体定义一个数组a[100],每一项都都包含a[i].s,a[i].e这两项。假设这100项按照a[i].s由小到大进行排序(具体怎样排序一会会在快排函数里面进行讲解),等把这100项排序按a[i].s好,那每一项的a[i].e也会跟着a[i].s走,因为他俩是一只绑定在一块的。打个恰当的例子,期末考试每个人都有各科的分(假设有七科,接可以在结构体里面定义七个变量),一般是按总成绩排名,假设某个人总成绩第10名,但是他的数学成绩是第一名,这样按数学成绩进行排名,他的排名就会在第一。总成绩排名时,他的所有成绩都在第十这样一行,但是如用按数学排名,他的所有成绩都是在第一行,这就是所谓的绑定。
快排函数:
1.快排函数需要头文件#include<algorithm>
2.假如对数组a[5]进行排序,采用sort(a,a+5);可以进行排序,如图所示
3.上述这种调用快排函数的最简单功能(快排函数功能特别强大,不仅可以对数进行排序,而且还能对字符,甚至字符串也能进行排序),咱们这一题需要的时按结构体里面的某一项进行排序。比如这一题,可以先定义一个结构体dd,再写一个cmp函数
struct dd { int s;//节目开始时间 int e;//节目结束时间 }a[101];
bool cmp(dd a,dd b) { return a.e<b.e; }
在cmp函数中,参数是结构体定义的两个变量(每个变量都含有两个值,比如a变量含有的是a.s和a.e)上面的函数写法是对结束时间进行从小到大排序;如果小于号改为大于号,则是从大到小进行排序;如果cmp函数里面的a.e和b.e改为a.s和b.s则是对节目开始时间进行排序。这两条很重要,是对结构体排序的方法。
下面说一下怎样遍历求最多能看多少完整的节目:
1.排序后的第一个节目肯定是符合要求的(自己可以想想为什么)
2.用一个变量t记录当前符合条件的结束时间,进行遍历时,只需要判断如果t小于等于个节目的开始时间,那这个节目就符合要求。
3.若是上面两步不太理解,可以参考着下面的代码,在演草纸上根据循环一步一步模拟一遍。
下面看具体代码:
#include<iostream>
#include<algorithm>
using namespace std;
struct dd
{
int s;//节目开始时间
int e;//节目结束时间
}a[101];
bool cmp(dd a,dd b)
{
return a.e<b.e;
}
int main()
{
int i,n;
while(cin>>n&&n)
{
int count=1,t;//count统计能看多少个完整节目
for(i=0;i<n;i++)
cin>>a[i].s>>a[i].e;
sort(a,a+n,cmp);//按照节目结束时间进行排序
t=a[0].e;
for(i=1;i<n;i++)//进行遍历,看有多少个节目符合条件
{
if(t<=a[i].s)
{
t=a[i].e;
count++;
}
}
cout<<count<<endl;
}
return 0;
}
这题最要的知识点有两个:结构体存储和结构体排序