[HNOI2008]水平可见直线

Time Limit: 1 Sec    Memory Limit: 162 MB

Description

[HNOI2008]水平可见直线

Input

第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi

Output

从小到大输出可见直线的编号,两两中间用空格隔开.

Sample Input

3
-1 0
1 0
0 0

Sample Output

1 2
 
 
 
题解:这题很像半平面交,不过只求半个,所以只要简单的用一个栈维护就可以了。
      具体做法就是先按斜率由小到大排序,然后依次处理,将当前直线与栈顶直线求交点,然后判断交点在栈顶减1的直线的左侧还是右侧(假定每一条直线是方向自左向右的向量,通过求叉积判左右),在右侧就踢掉栈顶的直线,一直做到可行。最后入栈。
 
错误:直线判平行一开始只做了一次。。其实一直要做到踢完所有平行的。(反正就是很水的错。。还Output Limit Exceed。。。)
 
AC CODE
 
program hy_1007;
const eps=1e- 7 ;
type line= record
             x1,y1,x2,y2: extended ;
           end ;
      dotype= record
               x,y: extended ;
             end ;
var l: array [ 1..50000 ] of line;
     k,b: array [ 1..50000 ] of extended ;
     a,stack: array [ 1..50000 ] of longint ;
     n,i,top: longint ;
     dott:dotype;
//============================================================================
procedure qsort(s,t: longint );
var i,j,tt: longint ;
     kk: extended ;
begin
   kk:=k[a[(s+t) div 2 ]]; i:=s; j:=t;
   repeat
     while k[a[i]]<kk do inc(i);
     while k[a[j]]>kk do dec(j);
     if i<=j then
     begin
       tt:=a[i]; a[i]:=a[j]; a[j]:=tt;
       inc(i); dec(j);
     end ;
   until i>j;
   if j>s then qsort(s,j);
   if i<t then qsort(i,t);
end ;
//============================================================================
procedure qsort2(s,t: longint );
var kk,i,j,tt: longint ;
begin
   kk:=stack[(s+t) div 2 ]; i:=s; j:=t;
   repeat
     while stack[i]<kk do inc(i);
     while stack[j]>kk do dec(j);
     if i<=j then
     begin
       tt:=stack[i]; stack[i]:=stack[j]; stack[j]:=tt;
       inc(i); dec(j);
     end ;
   until i>j;
   if j>s then qsort2(s,j);
   if i<t then qsort2(i,t);
end ;
//============================================================================
function dot(a,b:line):dotype;
var s1,s2,k: extended ;
begin
   s1:=(b . x1-a . x1)*(a . y2-a . y1)-(a . x2-a . x1)*(b . y1-a . y1);
   s2:=(a . x2-a . x1)*(b . y2-a . y1)-(b . x2-a . x1)*(a . y2-a . y1);
   k:=s1/(s1+s2);
   dot . x:=b . x1+(b . x2-b . x1)*k;
   dot . y:=b . y1+(b . y2-b . y1)*k;
end ;
//============================================================================
function right(a:dotype; b:line): boolean ;
begin
   if (b . x2-b . x1)*(a . y-b . y1)-(a . x-b . x1)*(b . y2-b . y1)<=eps then
   exit( true ) else exit( false );
end ;
//============================================================================
begin
   readln(n);
   for i:= 1 to n do
   begin
     a[i]:=i; readln(k[i],b[i]);
     l[i].x1:=- 1000 ; l[i].x2:= 1000 ;
     l[i].y1:=l[i].x1*k[i]+b[i];
     l[i].y2:=l[i].x2*k[i]+b[i];
   end ; qsort( 1 ,n);
   stack[ 1 ]:=a[ 1 ]; top:= 1 ;
   for i:= 2 to n do
   begin
     while top> 0 do   //错在这里了。。原来只是判断了一次,就跳掉了。
       if (k[stack[top]]=k[a[i]]) and (b[a[i]]>b[stack[top]]) then dec(top) else break;
     if k[a[i]]=k[stack[top]] then continue;  
     while top> 1 do
     begin
       dott:=dot(l[stack[top]],l[a[i]]);
       if right(dott,l[stack[top- 1 ]]) then dec(top) else break;
     end ;
     inc(top); stack[top]:=a[i];
   end ;
   qsort2( 1 ,top);
   for i:= 1 to top do write (stack[i], ' ' );
end .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值