区间重合判断[poj2808 校门外的树]
题目:http://bailian.openjudge.cn/practice/2808/
参考了文章,重写了代码:http://www.cnblogs.com/youxin/p/3266617.html(注:原文解法2代码有误)
解法1:以空间换时间
#include <iostream> using namespace std; int main() { int L, M, i, start, end, count; bool trees[10001]; for (i = 0; i < 10001; i++) trees[i] = true; count = 0; cin >> L >> M; for (i = 0; i < M; i++){ cin >> start >> end; while (start <= end){ trees[start] = false; start++; } } for (i = 0; i <= L; i++) if(trees[i] == true) count++; cout << count; return 0; }
如何马路长度L极大,比如40亿,以至于无法开设这么大的数组空间,此种解法就失效了。此时可以用解法2:先对区间按照开始时间start升序排列,然后当其他区间start小于初始区间(用temp表示)end时,表明这两个区间有重合,合并之(及修改temp.end)。由于按照区间起始start排序过了,只要start不小于初始区间end,则后面的区间就没有与初始区间重叠的区间了,此时将temp区间长度加到count上,并且将temp变为和前面区间无重叠的新区间,继续向下扫描。
解法2:区间合并
#include <stdio.h> #include <stdlib.h> #define M_MAX 100+1 typedef struct Area{ int start; int end; }Area; int CompareArea(const void *a, const void *b) { return ((Area *)a)->start - ((Area *)b)->start; } int main() { Area area[M_MAX], temp; int L, M, count = 0; scanf("%d%d", &L, &M); for (int i = 0; i < M; i++){ scanf("%d%d", &area[i].start, &area[i].end); } qsort(area, M, sizeof(Area), CompareArea); //区间按照开始时间升序排列 temp = area[0]; for (int i = 1; i < M; i++){ if (area[i].start <= temp.end){ if(area[i].end > temp.end) temp.end = area[i].end; } else{ count += temp.end - temp.start + 1; temp = area[i]; } } count += temp.end - temp.start + 1; printf("%d", L+1-count); return 0; }
编程之美也有类似的这个题目,其实,种树问题本质是区间重合判断。
一,问题:
1. 给定一个源区间[x,y]和N个无序的目标区间[x1,y1] [x2,y2] ... [xn,yn],判断源区间[x,y]是不是在目标区间内。
2. 给定一个窗口区域和系统界面上的N个窗口,判断这个窗口区域是否被已有的窗口覆盖。
第一题源代码:
按照编程之美给出的提示。 先用区间的左边界值对目标区间进行排序O(nlogn),对排好序的区间进行合并O(n),对每次待查找的源区间,用二分查出其左右两边界点分别处于合并后的哪个源区间中O(logn),若属于同一个源区间则说明其在目标区间中,否则就说明不在。(为什么可以二分法)