UVa live 3905 掃描線

【題目鏈接】
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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章