la3905 Meteor 流星 事件触发

来源:互联网 发布:好听的网络歌曲虾米 编辑:程序博客网 时间:2024/04/29 16:32

这个题目也是以前看过的 当时没有敲的勇气。今天看懂了。
题目实在是太巧妙了啊。。acm的真题果然不一般。



在一个平面内有一个矩形

然后给出n个流动的流星的初始位置和速度向量
求出最多同时多少个流星在这个矩形内
还有 这个矩形边界上的流星不算
矩形左下角是0.0 右上角是 w h
每个流星 四个int 初始位置 x y 和移动向量 a b


数据范围是 w h n, 1-10w  初始位置 正负20w 
a 和 b 不同时是0
也就说有可能有一个是0.。


题解 首先流星的轨迹没有意义 有意义的是 他出现在矩形内的时间段
所以说 就是抽象出 给出最多n个开区间,最多是因为有的流星永远不会过去。就不算了


把所有开区间 不重叠的画在图数轴上 现在想象 有一个轴
从0开始 一直右移 能交叉的最多的区间就是答案。。
这样就用到神思想了。。触发事件。
每次遇到一个左断点  cnt ++ 右端点 cnt--
还要考虑 如果某个点 同时有左 和 右端点 那肯定要先减再加。。排序的时候要注意。




想清楚了这个 思想后。。 就有点豁然开朗了。
但是还有一个不太好解决的问题。。就是确定一个流星的区间端点 
也就是什么时候进入到矩形 什么时候离开。


第一个要明白 进去的话 要 x 和y 都进去才进去了。
出去的话。一个走了就出去了。

#include<iostream>#include<cstdio>#include<algorithm>// use max and minusing namespace std;const int maxn=100000+10;struct Event{//事件 有double的时间和 int的 type 0进 1 出    double t;    int type;    bool operator <(const Event & e)const    {        return t<e.t || (t==e.t && type > e.type);    }} ;Event event[maxn*2];//注意这里有个乘2  一个流星会触发两事件void update(int x,int a,int w,double &l,double & r){    if(a==0)//速度向量    {        if(x<=0 || x>=w) r=l-1;// no ans    }    else if(a>0)//正方向    {        l=max(l,-(double)x/a);//x/a是路程除速度 加符号是因为 x在左边 小于0的话 要正的 x大于0的话 就取0 因为本来就在 或者本来就不再        r=min(r,(double)(w-x)/a);    }    else    {        l=max(l,(double)(w-x)/a);        r=min(r,-(double)x/a);    }}int main(){        //freopen("/home/gl/in","r",stdin);        int T;scanf("%d",&T);        while(T--)        {            int w,h,n,num=0,x,y,a,b;            scanf("%d %d %d",&w,&h,&n);            for(int i=0;i<n;++i)            {                scanf("%d %d %d %d",&x,&y,&a,&b);                double L=0,R=1e9;//L 和 R传引用 进入 和出去的时间                update(x,a,w,L,R);//先更新 x在范围内的时间                update(y,b,h,L,R);//再更新 y在范围内的时间                if(R>L)//表示有意义                {                    event[num++]=(Event){L,0};//注意强制转换的方法                    event[num++]=(Event){R,1};                }            }            sort(event,event+num);//按照事件出现的顺序排序            int ans=0,cnt=0;            for(int i=0;i<num;++i)            {                if(event[i].type==0) ans=max(ans,++cnt);                else cnt--;            }            printf("%d\n",ans);        }        return 0;}












原创粉丝点击