LA3905流星

来源:互联网 发布:安哥拉伊斯兰教 知乎 编辑:程序博客网 时间:2024/04/28 20:35
题意:
      在一个二维平面上有n个流星,每个流星有自己的初始位置和速度,有一个照相机,张相机的可视范围是一个矩形框,左下角(0,0)右上角(w ,h),然后问你相机的矩形内出现的最多的流星数是多少? 


思路:
      感觉是一道很不错的题目,想到流星数目,第一反应就是可以把他转化成时间段,我们求出每个流星的进入相机时间,和出相机时间,这样就会得到一个时间段,流星的最大
数量也就是时间段的最大重叠部分,这个不解释了应该不难理解,现在问题就来了,我们怎么求得所有的时间段呢?一开始我也感觉很麻烦,然后在白书上学了一个比较方便的方法,我们求时间段可以先把流星分解了,x,y单独算,进入的时间肯定是进x进y的最大值,出去的时间肯定是出x,出y的最小值,这样我们分别求完之后就ok了,如果L>=R就证明没有在相机范围内出现过,下面给出求L,R的代码
void Update(int x ,int a ,int w ,double& L ,double& R)
{
   if(a == 0)
   {
       if(x <= 0 || x >= w) R = L - 1; //永远也进步了相机
   }
   else if(a > 0)//往上跑 
   {
      L = Max(L ,-(double)x / a);
      R = Min(R ,(double)(w - x) / a);
   }
   else//往下跑
   {
      L = Max(L ,(double)(w - x) / a);//理解不了的注意这里的a是负的
      R = Min(R ,-(double)x / a); 
   }
           
}


求x,y的时候都是用的上面的那个,只不过传的参数不一样罢了,具体细节可以看代码。
  这样我们就得到了所有流星的时间段L,R(L>=R的是不满足的,直接丢弃),然后就是求区间的最大重叠面积了,这个也比较好求,如果你不嫌麻烦可以写线段树贪心去求,时间复杂度是O(n*log(n))的,不过有一个更省事更快的方法,就是扫面线法O(n)<其实这么说有漏洞,因为扫描线涉及到排序,排序是O(n*log(n))的,这个地方大家知道就行了>,我们可以把所有端点都扔进结构体数组里,然后按照时间从小到大排序,如果时间相等那么就后端点在前面(这样的原因是题目中说在相机边框上的不算,如果算的话就入端点在前面),排序之后直接扫一遍,遇到前端点就++,后端点就--,过程中最大的值就是答案,这个应该很好理解,不理解的在纸上画一画,每次变化的时候都是在端点上变化的,这个就是经典的扫描线想法,扫描线也可以配合着线段树应用,求重叠面积,体积,周长啥的。这个题目还有一个小小的优化(白书上说的),我们可以躲开浮点运算,因为整个程序里涉及到的除法就是除以速度,速度的范围是绝对值<=10,那么我们直接把被除数扩大1,2,3..10的最小公倍数2520倍就行了,这样保证都是整除,至于为什么我想不用我解释了。






#include<stdio.h>
#include<string.h>
#include<algorithm>


#define N 100000 + 10


using namespace std;




typedef struct
{
    int mk;
    double time;
}NODE;


NODE node[N+N];


bool camp(NODE a ,NODE b)
{
     return a.time < b.time || a.time == b.time && a.mk < b.mk;
}


double Max(double x ,double y)
{
    return x > y ? x : y;
}


double Min(double x ,double y)
{
    return x < y ? x : y;
}


void Update(int x ,int a ,int w ,double& L ,double& R)
{
   if(a == 0)
   {
       if(x <= 0 || x >= w) R = L - 1;
   }
   else if(a > 0) 
   {
      L = Max(L ,-(double)x / a);
      R = Min(R ,(double)(w - x) / a);
   }
   else
   {
      L = Max(L ,(double)(w - x) / a);
      R = Min(R ,-(double)x / a); 
   }
           
}


int main ()
{
    int t ,w ,h ,n ,i;
    int x ,y ,a ,b;
    scanf("%d" ,&t);
    while(t--)
    {
       scanf("%d %d" ,&w ,&h);
       scanf("%d" ,&n);
       int nowid = 0;
       for(i = 1 ;i <= n ;i ++)
       {
          scanf("%d %d %d %d" ,&x ,&y ,&a ,&b);
          double L = 0 ,R = 999999999;
          Update(x ,a ,w ,L ,R);
          Update(y ,b ,h ,L ,R);
          if(L < R)
          {
             node[++nowid].time = L;
             node[nowid].mk = 1;
             node[++nowid].time = R;
             node[nowid].mk = -1;
          }
       }
       int Ans = 0;
       sort(node + 1 ,node + nowid + 1 ,camp);
       int sum = 0;
       for(i = 1 ;i <= nowid ;i ++)
       {
          sum += node[i].mk;
          if(Ans < sum) Ans = sum;
       }
       printf("%d\n" ,Ans);
    }
    return 0;  
}
   




//排除浮点型运算
void Update(int x ,int a ,int w ,int& L ,int& R)
{
   if(a == 0)
   {
       if(x <= 0 || x >= w) R = L - 1;
   }
   else if(a > 0) 
   {
      L = Max(L ,-x * 2520 / a);
      R = Min(R ,(w - x) * 2520 / a);
   }
   else
   {
      L = Max(L ,(w - x) * 2520/ a);
      R = Min(R ,-x * 2520/ a); 
   }
           
}





0 0
原创粉丝点击