二分判断线段相交

2.1 题目描述
路上挂着一些灯,第 i 个灯坐标为(xi, yi) 。每个灯的照射范围为一个三角形,半张角为 zi 。
你有一架飞机,但是只能飞固定高度。由于未知原因(目测秋锅农气过重),飞机只能在光下
飞行。你的任务是找一个最大的高度来从 L 飞到R 。
如图,红线所示高度是一个合法高度,但是不是最高的。


2.2 输入格式
第一行三个数 n,L,R ,其中n 是整数,表示灯的个数。
接下来 n行,每行 3 个实数x, y, z ,描述一个灯。
2.3 输出格式
一行一个数,表示最大高度。至少保留 6 位小数。你的答案正确,当且仅当与标准输出相对误差或绝对误差不超过 10− 。

2.4 样例输入
2 3.2 7.3
3.2 4.7 28
7.3 4.2 75
2.5 样例输出
3.300759642
2.6 数据范围
对于 30%的数据:n ≤ 5, y ≤ 5
对于 60%的数据:n ≤ 30000
对于 100%的数据:n ≤ 10^5, 0 < y ≤ 10^3, 15 ≤ z ≤ 75,−10^3≤ x,L,R ≤ 10^3

 

好吧,大神们一眼看出的二分答案 = =。

小小地注意一下需要转弧度制。

把三角形按照x[i]从小到大离散化之后,从1一直扫到n,满足now(现在位置)>x[i]-tmp 并且now<x[i]+tmp就可以将now移到x[i]+tmp。

如果now能移到终点则是可行的。

program Neayo;
const
        inf='light.in';
        ouf='light.out';
var
        i,j,k,m,n:longint;
        exp,sr,sl,l,r:extended;
        x,y,tan:array[0..100001]of extended;
procedure qsort(l,r:longint);
var tmp,xx:extended;
    i,j:longint;
begin
     i:=l;j:=r;
     xx:=x[l+random(r-l+1)];
     repeat
           while x[i]<xx do inc(i);
           while x[j]>xx do dec(j);
           if i<=j then
           begin
                tmp:=x[i];x[i]:=x[j];x[j]:=tmp;
                tmp:=y[i];y[i]:=y[j];y[j]:=tmp;
                tmp:=tan[i];tan[i]:=tan[j];tan[j]:=tmp;
                inc(i);
                dec(j);
           end;
     until(i>j);
     if i<r then qsort(i,r);
     if l<j then qsort(l,j);
end;
procedure init;
var tmp,z:extended;
begin
     assign(input,inf);assign(output,ouf);
     reset(input);rewrite(output);
     readln(n,sl,sr);
     tmp:=pi/180;
     for i:=1 to n do
     begin
          readln(x[i],y[i],z);
          tan[i]:=sin(z*tmp)/cos(z*tmp);
     end;
     qsort(1,n);
     close(input);
end;
function judge(h:extended):boolean;
var now,tmp:extended;
begin
     now:=sl;
     for i:=1 to n do
     begin
          tmp:=(y[i]-h)*tan[i];
          if now>x[i]-tmp then
          begin
               if x[i]+tmp>now then now:=tmp+x[i];
          end;
     end;
     if now>sr then exit(true)
     else exit(false);
end;
procedure go;
begin
     l:=0;
     r:=1000;
     exp:=1e-8;
     while r-l>exp do
     begin
          if judge((r+l)/2) then  l:=(r+l)/2
          else r:=(r+l)/2;
     end;
     writeln(l:0:7);
end;
begin
     init;
     go;
     close(output);
end.
posted @ 2012-11-06 15:20  neayo  阅读(175)  评论(0编辑  收藏  举报