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; } |
【关键词】:物理模型,边界处理 |
相关文章推荐
- UVALive - 3905 —— Meteor 流星
- uvalive3905(扫描法)
- UVALive - 3905 Meteor 统计
- uvalive 3905 扫描线:求包含区间最多的点
- Meteor UVALive - 3905 (区间扫描)
- UVaLive 3905 Meteor (扫描线)
- UVALive - 3905 [Meteor]
- 【UVALive 3905】BUPT 2015 newbie practice #2 div2-D-3905 - Meteor
- UVALive 3905-Meteor-扫描线算法
- Uva-Live 3905-Meteor
- UVALive - 4255 - Guess (拓扑排序)
- UVAlive3532 Nuclear Plants
- UVALive4287 hdu2767 hdu3836 强连通
- Uvalive 6855 Banks
- UVALive-7528-Beehive
- acm 乘法逆元 或线段树 UVALive 5798
- UVALive 3703 (LA 3703) Billing Tables Trie树
- G - Meeting Room Arrangement UVALive - 6606——动态规划
- UVALive 5902 Movie collection(树状数组)
- Just Sum It [UvaLive 5063] DP+组合数