您的位置:首页 > 其它

UVa live 3905 扫描线

2015-12-12 12:13 453 查看
【题目链接】

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16454

【解题报告】

为了学习线段树的扫描线算法,就特地来做一做扫描线的题目。题意很简单,一个二维平面,给一个固定的矩形,N个流星,每个流星给出初始坐标,和位移的矢量。求问矩形里最多能同时有多少颗流星。

这道题目在《训练指南》中作为第一章的例题出现。

我认为有两个关键点:

1.如何计算流星穿过矩形的时间段。

2.对于N颗流星得到他的穿进时间点和穿出时间点,扫描过程中遇到端点如何处理,遇到左端点和右端点重合的情况应该怎么处理。

其中第一个点在于能不能写出清晰而又简洁的代码(设计)。第二个点在于是否能考虑到并正确处理边界情况(算法)。

虽然是一道很简单的构造题目,仍然值得重视。

【参考代码】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

const int INF=1e9;
const int maxn=100000+50;

int w,h,n;

struct Node
{
double time;
int type;
bool operator < (  const Node& a )const
{
return (time<a.time) || (  time==a.time && type>a.type );
}
};
Node event[maxn*2];

//   0<x+at<w
void update(  int x, int a, int w, double& L, double& R  )
{
if( a==0 )
{
if(  x>=w || x<=0  )   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()
{
//  freopen(  "3905.txt","r",stdin );
int T; cin>>T;
while( T-- )
{
int w,h,n,e=0;
scanf( "%d%d%d",&w,&h,&n );
for(  int i=0; i<n; i++ )
{
int x,y,a,b;
scanf( "%d%d%d%d", &x, &y, &a, &b );
double L=0.0, R=1e9;
update(  x,a,w,L,R  );
update(  y,b,h,L,R );
//  cout<<L<<"  "<<R<<endl;
if( L<R )
{
event[e++]=(Node){ L,0 };
event[e++]=(Node){ R,1 };
}
}
sort( event , event+e );
// cout<<endl;
int ans=0,cnt=0;
for( int i=0; i<e; i++ )
{
if(  event[i].type==1 ) cnt--;//遇到右端点,-1
else ans=max(  ans, ++cnt );//最大的一定在某个左端点处
}
printf( "%d\n",ans );
}

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