【CodeVS3201】奶牛代理商 XI

【Description】

  小徐是USACO中国区的奶牛代理商,专门销售质优价廉的“FJ”牌奶牛。
  有一天,她正在卖奶牛,突然觉得很孤单,想把她的朋友接来。
可这要花一大笔钱。
  她有N个牛棚,想让你帮她重新围一块地,包含所有牛棚,且是凸多边形(否则奶牛会撞墙角)
  她现在经济很困难,不用你关心省下的地能卖多少钱,只要能让围栏最短,花最少的钱。
  请你计算围栏的最短长度。


【Input】

  N
  每个牛棚的坐标(整数)


【Output】

  最短长度(保留2位小数)


【Sample Input】

4
0 3
3 0
0 0
1 1

【Sample Output】

10.24

【Data Size and Hint】

   N1000
   |X|,|Y|500


【Solution】

  题目是形象地告诉你求一个能包进所有点的凸包周长。
  具体方法参考LRJ黑书上的叉积部分和白书上Andrew算法部分。
  参考代码如下:
  

type point = record
               x,y:longint;
             end;
var n,m,i:longint;
    ans:double;
    p:array[0..1010] of point;
    stack:array[0..1010] of point;
procedure init; //读入
  var i:longint;
  begin
    readln(n);
    for i:=1 to n do readln(p[i].x,p[i].y);
  end;
procedure qsort(l,r:longint);  //按x第一关键字,y第二关键字排序
  var i,j,mid,mid2:longint;
      tmp:point;
  begin
    i:=l; j:=r; mid:=p[(i+j) shr 1].x; mid2:=p[(i+j) shr 1].y;
    repeat
      while (p[i].x<mid) or ((p[i].x=mid) and (p[i].y<mid2)) do inc(i);
      while (p[j].x>mid) or ((p[j].x=mid) and (p[j].y>mid2)) do dec(j);
      if i<=j then begin
        tmp:=p[i]; p[i]:=p[j]; p[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;
function Cross(a,b:point):longint;  //求叉积
  begin
    exit(a.x*b.y-b.x*a.y);
  end;
function minus(a,b:point):point;  //求向量差
  begin
    minus.x:=a.x-b.x; minus.y:=a.y-b.y;
  end;
procedure ConvexHull;  //Andrew求凸包
  var i,k:longint;
  begin
    m:=1;
    fillchar(stack,sizeof(stack),0);
    for i:=1 to n do begin
      while (m>2) and (Cross(minus(stack[m-1],stack[m-2]),
                             minus(p[i],stack[m-2]))<=0)
        do dec(m);
      stack[m]:=p[i]; inc(m);
    end;
    k:=m;
    for i:=n-1 downto 1 do begin
      while (m>k) and (Cross(minus(stack[m-1],stack[m-2]),
                             minus(p[i],stack[m-2]))<=0)
        do dec(m);
      stack[m]:=p[i]; inc(m);
    end;
  end;
function calc(a,b:point):double;  //计算两点间距离
  begin
    exit(sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)));
  end;
procedure print;  //输出周长
  var i:longint;
  begin
    for i:=2 to m-1 do
      ans:=ans+calc(stack[i],stack[i-1]);
    writeln(ans:0:2);
  end;
begin
  init;
  qsort(1,n);
  ConvexHull;
  print;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值