uva 1398 Meteor
https://vjudge.net/problem/UVA-1398
!!!:uvalive炸了,简直有毒,标程提交都有错。
题意:
一个矩形的相机,左下坐标是(0,0),右上坐标是(w,h),在这个坐标系内,有许多正在飞的流星,每个流星用两个向量表示,一个表示初始位置,另一个表示速度向量,问照相机范围内星星最多的时候有多少颗。
在相机边界的点是不在相机范围内的。(即为开区间。)
思路:
扫描线的第一道题。。。参考训练指南。
首先,流星在照相机范围内是有一个时间范围的,于是问题遍转化成了在哪个时刻照相机范围内的流行最多,那么转化成数学问题就是流星在相机内的时间段转换成数轴上的一个个区间,那么我们用垂直于数轴的一根直线去扫数轴,那么在某一个区间范围内,
这根直线与一定数量的区间相交,并且这个区间的数量最大,那么这就是可以看到流星的最大数量。
时间范围用不等式求解,0 < at + x < w,0 < bt + y < h行(开区间),那个update函数的作用就是这个,理解了相当长的一段时间。。。
那么对于每一个流星的时间段,可以拆分成一个开始事件和一个结束事件,然后把每个流星排序,假设排好了序,那么当统计数量的时候,遇到了一个开始事件,就把数量加一,遇到了一个结束事件,那么就把数量减一,这样一边遍历,一边维护。
接下来,讲讲排序的问题,当遇到一个事件的结束和一个事件的开始时间相同的时候,应该把哪个排在前面呢?
因为是开区间,而此时开始的那个事件还未进入相机,但是结束的那个事件已经不再相机之中了,所以在排序的时候,如果说时间相同,那么把结束事件排在前面,把开始事件排在后面。
还有计算时间的时候,如果速度为0,并且坐标不在给定的范围内的,那么就不应该计算这颗流星。(记住是 || 不是 && 在这里debug半天,最近老是写炸Orz)
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 6 void caltime(int x,int a,int w,double &l,double &r) 7 { 8 if (a == 0) 9 { 10 if (x <= 0 || x >= w) l = 1e10,r = 0; 11 } 12 else if (a > 0) 13 { 14 l = max(l,-(double) x / a); 15 r = min(r,(double)(w - x) / a); 16 } 17 else 18 { 19 l = max(l,(double)(w - x) / a); 20 r = min(r,-(double)x / a); 21 } 22 } 23 24 struct node 25 { 26 double x; 27 int ty; 28 } c[200005]; 29 30 bool cmp(node aa,node bb) 31 { 32 if (aa.x == bb.x) return aa.ty < bb.ty; 33 return aa.x < bb.x; 34 } 35 36 int main() 37 { 38 int t; 39 40 scanf("%d",&t); 41 42 while (t--) 43 { 44 int w,h; 45 46 scanf("%d%d",&w,&h); 47 48 int n; 49 50 scanf("%d",&n); 51 52 int cnt = 0; 53 54 for (int i = 0;i < n;i++) 55 { 56 int x,y,a,b; 57 58 scanf("%d%d%d%d",&x,&y,&a,&b); 59 60 double l = 0,r = 1e10; 61 62 caltime(x,a,w,l,r); 63 64 caltime(y,b,h,l,r); 65 66 //if (y == h && b == 0) printf("**"); 67 68 if (l < r) 69 { 70 //printf("%f %f\n",l,r); 71 c[cnt++] = (node){l,1}; 72 c[cnt++] = (node){r,0}; 73 } 74 } 75 76 sort(c,c+cnt,cmp); 77 78 int ans = 0; 79 80 int num = 0; 81 82 for (int i = 0;i < cnt;i++) 83 { 84 //printf("%f %d **\n",c[i].x,c[i].ty); 85 86 if (c[i].ty == 0) num--; 87 else num++; 88 89 ans = max(ans,num); 90 } 91 92 printf("%d\n",ans); 93 } 94 95 return 0; 96 }