题目描述
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是11米。我们可以把马路看成一个数轴,马路的一端在数轴00的位置,另一端在LL的位置;数轴上的每个整数点,即0,1,2,…,L0,1,2,…,L,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入格式
第一行有22个整数 L(1 \le L \le 10000)L(1≤L≤10000) 和 M(1 \le M \le 100)M(1≤M≤100),LL代表马路的长度,MM代表区域的数目,LL和MM之间用一个空格隔开。
接下来的MM行每行包含22个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。
输出格式
11个整数,表示马路上剩余的树的数目。
输入输出样例
500 3 150 300 100 200 470 471
298
说明/提示
NOIP2005普及组第二题
对于20\%20%的数据,区域之间没有重合的部分;
对于其它的数据,区域之间有重合的情况。
解决思路
这条题目有两个解法,简单暴力的一种,是设置一个L长度的数组作为标记,如果树被移走,置为1,最后统计1的数目,这种解法中,对重复的置1效果是相同的,但是空间复杂度高;另外很自然的一种想法是判断是否有重叠,有重叠则合并两个段,我按这个思路完成代码,但是只能通过40%的用例,导出洛谷的输入,发现可能存在这种输入情况: [2,5] [6, 8], [3,7],第一段和第二段不重叠,但是第三段和第一段、第三段和第二段都存在重叠,按自然的输入顺序合并,最后的段是[2, 7] [6, 8],显然存在错误,为解决这种问题,就要先对输入的段按左边界增序排序,然后再处理。
代码
#include
#include
using namespace std;
struct seg {
int begin;
int end;
};
#define LENGTH(b, e) (e - b + 1)
int overlap(int a0, int a1, int b0, int b1)
{
return !(a1 < b0 || a0 > b1);
}
int calc(int L, int n, struct seg * array)
{
struct seg * elements = new struct seg [n];
int num = 0;
int i,j,k;
for(i=0; i
/*overlap ?*/
for(j=0; j
if(overlap(elements[j].begin, elements[j].end, array[i].begin, array[i].end)) {
elements[j].begin = min(elements[j].begin, array[i].begin);
elements[j].end = max(elements[j].end, array[i].end);
break;
}
}
/*not overlay*/
if(j >= num) {
elements[num].begin = array[i].begin;
elements[num].end = array[i].end;
num++;
}
}
int sum = 0;
for(i=0; i
if(elements[i].begin == -1) {
continue;
}
sum += (elements[i].end - elements[i].begin + 1);
//printf("begin:%d end:%d\r\n", elements[i].begin, elements[i].end);
}
return L + 1 - sum;
}
bool cmp(struct seg &a, struct seg &b)
{
return a.begin < b.begin;
}
int main(int argc, char **argv)
{
int L = 500;
int num = 3;
struct seg *array;
while(cin >> L)
{
cin >> num;
array = new struct seg [num];
for(int i=0; i
cin >> array[i].begin;
cin >> array[i].end;
}
sort(array, array + num, cmp);
cout << calc(L, num, array) << endl;
}
return 0;
}