您的位置:首页 > 其它

UVALive3905 流星

2014-01-18 17:46 337 查看
UVALive3905 流星

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=283&page=show_problem&problem=1906

【题目描述】:在夜空下,放置一个摄像头,已知,摄像头左下角在(0,0),右上角由输入给定(w,h)。再给出n颗流星的初始位置(夜空范围内,不一定在摄像头范围内),矢量速度(VX,VY),求从开始,整个过程中,镜头内最多看到几颗流星。注意,在流星在边框上时看不到。

【思路分析】:

【一】遇到物理问题一般退化成数字模型。列两个不等式

0<x+vx*t<w (注意是开区间)

0<y+vy*t<h

【二】这样能解出一个关于变量t的公共区间,但是要注意,随着vx的正负,除完可能要变号。书上提供一个很好的方法,详细见代码,两边逼近最后的区间。

这样我们就得到了n个区间(当然,如果区间左端点大于等于右端点,应该舍去)

最终问题变成,在这数轴上的n条线段,找出一条t=x的竖线,使它穿过的横线最多。X即为所求的解。

【三】我们假设从负无穷点处开始移动这条竖线,当它从一条直线的左端点偏左(+eps),这条竖线上多穿了一条,从一条直线的右端点(这里不用考虑eps了,为什么,因为本身是开区间了),穿过的线少了一条。

但是我们不可能模拟一条直线移动(精度不够)。但是我们是能够跳跃的,即只考虑两个端点,所以先将线段排序(1、左端小的优先;2、右端小的优先)。排序的目的是O(n)的复杂度的扫描,不重不漏。

【四】额外思考:如果不排序呢?我们可以枚举每条边,在它的右端点靠左一点的位置t检测所有边是否包含这个t,最终记录最大的边数即可。但是这样复杂度就成了N*N。而排序的方法约为Nlog2(N)+N.

【完整代码】:

#include<iostream>

#include<stdio.h>

#include<string.h>

#include<algorithm>

#include<stdlib.h>

#include<math.h>

#include<queue>

#include<vector>

#include<set>

#include<map>

#define MAXN 200000+5

#define MAXM 400000+5

#define oo 1e9

#define eps 0.001

#define PI acos(-1.0)//这个精确度高一些

#define REP1(i,n) for(int i=0;i<=(n);i++)

#define REP2(i,n) for(int i=1;i<=(n);i++)

#define LL long long

using namespace std;

struct Event

{

int lor;//左端点为1,右端点为2

double p;

Event(){}

Event(int ll,double pp){lor=ll;p=pp;}

bool operator <(const Event& x) const

{

if (p==x.p) return lor>x.lor;

else return p<x.p;

}

}event[MAXM];

int cas,w,h,n;

double l,r;

double maxd(double a,double b)

{

if (a>b) return a;else return b;

}

double mind(double a,double b)

{

if (a<b) return a;else return b;

}

void getVAL(double s,double v,double up)//满足0<s+vt<up

{

if (v==0)

if ( s<=0 || s>=up)//注意边界

r=l-1;//这个区间不存在

else return;//star将一直存在

if (v>0) {l=maxd(l,-s/v),r=mind(r,(up-s)/v);}

if (v<0) {l=maxd(l,(up-s)/v),r=mind(r,-s/v);}

return;

}

int main()

{

cin>>cas;

for(;cas;cas--)

{

cin>>w>>h>>n;

int cnt1=0;

for(int i=1;i<=n;i++)

{

double x,y,vx,vy;

cin>>x>>y>>vx>>vy;

l=0;r=oo;

getVAL(x,vx,w);

getVAL(y,vy,h);

if (l>=r) continue;

//保证区间有意义

event[cnt1++]=(Event){1,l};

event[cnt1++]=(Event){2,r};

}

sort(event,event+cnt1);

int add=0,ans=0;

for(int i=0;i<cnt1;i++)

{

if (event[i].lor==1) add++;else add--;

ans=max(ans,add);

}

cout<<ans<<endl;

}

return 0;

}


【关键词】:物理模型,边界处理

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: