uvaoj1398
题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4144
学会了新的打点方式,特点类似时间轴,从前向后扫。
细节注意 , 如果 两个事件,前一个的结尾 等一后一个的开始,则算一个事件。
#include<cstdio> #include<algorithm> using namespace std; #define max(a,b) a>b?a:b #define min(a,b) a<b?a:b #define INF 1<<30; double l ,r ; // L 开始进入的时间(必须是最大的,如只满足x到达界限内,而y没有那么,肯定没有进入区域内,所以最大的决定进入区域内) ,R结束出去的时间(必是最小的,同理,一个满足离开的,一定离开这个区域了) typedef struct eve { double e; int k; }eve; eve even[200005]; void update(int x ,int a ,int w) //膜拜作者!!! 这个函数复用性很高!太巧妙了 { if(a == 0) { if( x<= 0 || x >= w ) r =l-1; //巧妙的L,R,去除,有时去除不一定非要附一个特别的值,可以建立一种关系,是非常棒的想法 } else if(a > 0 ) //排除了擦边的情况 { l = max(l, -1.0*x/a); r = min(r,(w-x)*1.0/a); } else { l = max(l, (x-w)*-1.0/a ); r = min(r, x*-1.0/a); } } int cmp(eve a ,eve b) { return a.e < b.e || (a.e == b.e && a.k > b.k); } int main() { int n,m,i,top,ans,cnt; int x,y,a,b; int w,h; scanf("%d",&n); while(n--) { scanf("%d %d",&w,&h); scanf("%d",&m); top = 0; for( i = 0 ;i<m ;i++) { scanf("%d %d %d %d",&x,&y,&a,&b); l = 0;r =INF; update(x,a,w); update(y,b,h); //L,R不断的精确,它受横纵坐标及速度的限制! if(r - l > 1e-6) { even[top].e = l; even[top].k = 0; // printf("%f %d %d",even[top].e ,even[top].k ,top); top++; even[top].e = r; even[top].k = 1; // printf("%f %d %d",even[top].e ,even[top].k ,top); top++; } } sort(even,even+top ,cmp); ans = cnt = 0; for(i = 0;i<top;i++) { if(even[i].k == 0) { cnt++; ans = max(ans ,cnt); } else cnt--; } printf("%d\n",ans); } return 0; }