凸包

http://unbelievable.ycool.com/post.804688.html

 

 

呀呀....    自学凸包呀...

知道1些基本操作....


program prog3;
const maxt = 1000;
     maxn = 1000;
     inf = 'wudi3.in';
     ouf = 'wudi3.out';
type node = record
             x, y : longint;
           end;
var sum, n : array [1..maxt] of longint;
   c, p : array [1..maxt,1..maxn] of node;
   tot : longint;
   ans : extended;
   jiong : node;

procedure init;
var i : longint;
begin
 readln(n[tot]);
 for i:=1 to n[tot] do
   with p[tot,i] do readln(x,y);
end;

procedure qsort(l,r : longint);
var i,j : longint;
   tmp, t : node;

 function smaller(a,b:node):boolean;
 begin
   if (a.y<b.y) or ((a.y=b.y) and (a.x<b.x)) then smaller:=true
                                             else smaller:=false;
 end;

begin
 i:=l; j:=r; t:=p[tot,random(r-l)+1+l];
 repeat
   while (i<=j) and smaller(p[tot,i],t) do inc(i);
   while (i<=j) and smaller(t,p[tot,j]) do dec(j);
   if i<=j then begin
     tmp:=p[tot,i]; p[tot,i]:=p[tot,j]; p[tot,j]:=tmp;
     inc(i); dec(j);
   end;
 until i>j;
 if l<j then qsort(l,j);
 if i<r then qsort(i,r);
end;

function dbl(p0,p1,p2:node):longint;  // 叉积 ....
begin
 dbl:=(p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
end;

procedure convex;
var t, i, m: longint;

 procedure add(size,k:longint);  //  叉积为 负 入栈 ...否则弹出....
 begin
   while (m>=size+2) and (dbl(c[tot,m-1],c[tot,m],p[tot,k])>=0) do dec(m);
   inc(m); c[tot,m]:=p[tot,k];
 end;

begin
 c[tot,1]:=p[tot,1]; c[tot,2]:=p[tot,2]; m:=2;  // 逆时针...  
 for i:=3 to n[tot] do add(0,i);   // 先到顶 ...
 t:=m-1;
 for i:=n[tot]-1 downto 1 do add(t,i);  // 再下来....
 dec(m);
 n[tot]:=m;
end;

procedure area;  // 求凸包面积... 两两相邻的叉积和......
var i: longint;
   z : node;
begin
 z.x:=0; z.y:=0;
 sum[tot]:=0;
 for i:=1 to n[tot] do
   sum[tot]:=sum[tot]+dbl(z,c[tot,i],c[tot,i+1]);
 sum[tot]:=abs(sum[tot]);
end;

procedure out ;
var i : longint;
begin
 assign(output,ouf);rewrite(output);
{  for i:=1 to tot do
   writeln(sum[I]/2:0:2);}
 writeln(ans/2:0:2);
 close(output);
end;

procedure work;
var i : longint;

 function inside(k : longint):boolean;  // 判断 点是否在凸包内... 向引1条射线... 交了奇数根线段则在内...否则再外...
 var t, q, a, b, ct : longint;
     tmp : longint;
 begin
   ct:=0;
   for q:=1 to n[k] do begin
     t:=dbl(jiong,c[k,q],c[k,q+1]);  // 算叉积...
     if t=0 then begin  // 等于零 则在凸包边上...
       inside:=false; exit;
     end;
     a:=c[k,q].y; b:=c[k,q+1].y;  
     if a<b then begin  //保证是  上面的点到下面的点...(y轴)...
       tmp:=a; a:=b; b:=tmp;
       t:=-t;
     end;
     if (a>jiong.y) and (jiong.y>=b) and (t>0) then inc(ct);  // 此线段跨过这点...且是右手旋转...
   end;
   inside:=odd(ct);
 end;

begin
 for i:=1 to tot do
   if inside(i) then ans:=ans+sum[I];
end;

begin
 randomize;
 assign(input,inf);reset(input);
 repeat
   inc(tot);
   init;  //  输入段
   if n[tot]=-1 then break;
   qsort(1,n[tot]);  //  构建凸包之前要快排的吧...按Y从小到大..若相同则按X 从小到大....
   convex;  //  构建凸包....逆时针顺序....
   area;   //  求面积.... 就是以1个点为P0计算叉积....取个绝对值就OK 了
 until false;
 dec(tot);
 readln(jiong.x,jiong.y);
 close(input);
 work;
 out;
end.


 

posted @ 2008-12-05 15:32  jesonpeng  阅读(203)  评论(0)    收藏  举报