JZOJ1312.【USACO题库】5.1.1 Fencing the Cows圈奶牛

来源:互联网 发布:广发期货模拟软件 编辑:程序博客网 时间:2024/05/02 02:02

problem

题目描述
农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏。他建造的围栏必须包括他的奶牛喜欢吃草的所有地点。对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度。

PROGRAM NAME: fc

INPUT FORMAT

输入数据的第一行包括一个整数 N。N(0 <= N <= 10,000)表示农夫约翰想要围住的放牧点的数目。接下来 N 行,每行由两个实数组成,Xi 和 Yi,对应平面上的放牧点坐标(-1,000,000 <= Xi,Yi <= 1,000,000)。数字用小数表示。

SAMPLE INPUT (file fc.in)

4

4 8

4 12

5 9.3

7 8

OUTPUT FORMAT

输出必须包括一个实数,表示必须的围栏的长度。答案保留两位小数。

SAMPLE OUTPUT (file fc.out)

12.00
输入
输出
样例输入
样例输出
数据范围限制


analysis

由于本人心血来潮我重新写了另一篇排版更好看更好懂的凸包blog

凸包详解:http://blog.csdn.net/enjoy_pascal/article/details/78397028

好,看完了吗?理解了吗?
所以,这道题完全就是一道凸包裸题
我们用graham把凸包上的点全部求出,再计算凸包中两两相邻的点的距离和就可以了


code

新学的OIers建议别直接看代码,还是尽量手撸,自己理解理解

type        point=record                x,y:extended;        end;var        f:array[0..10000]of point;        angle:array[0..10000]of        record                x,y,value,dis:extended;        end;//x,y坐标,value角度,dis与原点距离        stack:array[0..10000]of longint;        row,rank:extended;        n,i,j,tot,up:longint;        ans:extended;function judge(ax,ay,bx,by,cx,cy:extended):extended;begin//判断点是否在直线左侧        exit(ax*by+cx*ay+bx*cy-cx*by-bx*ay-ax*cy);end;function arccot(xx,yy:extended):extended;begin//返回一个点连原点与x轴正半轴的夹角        if yy=0 then exit(0);        if xx=0 then exit(90);        arccot:=arctan(yy/xx)*180/pi;//计算几何,这里用pascal自带的三角函数arctan        if xx<0 then arccot:=arccot+180;end;procedure qsort(l,r:longint);var//快排,不解释        i,j:longint;        mid,mid1:extended;begin        i:=l;        j:=r;        mid:=angle[(l+r)shr 1].value;        mid1:=angle[(l+r)shr 1].dis;        repeat                while (angle[i].value<mid)or(angle[i].value=mid)and(angle[i].dis<mid1)do inc(i);                while (angle[j].value>mid)or(angle[j].value=mid)and(angle[j].dis>mid1)do dec(j);                if i<=j then                begin                        angle[0]:=angle[i];                        angle[i]:=angle[j];                        angle[j]:=angle[0];                        inc(i);                        dec(j);                end;        until i>j;        if l<j then qsort(l,j);        if i<r then qsort(i,r);end;begin        readln(n);        rank:=maxlongint;        for i:=1 to n do        with f[i] do        begin                readln(x,y);                if y<rank then                begin                        row:=x;                        rank:=y;                end;//记录最底下的点的行列值        end;        for i:=1 to n do        with f[i] do        begin                x:=x-row;                y:=y-rank;        end;//把所有点平移一下,使没有点会在三四象限内        tot:=1;        for i:=1 to n do        with f[i] do        if (x<>0)or(y<>0) then        begin                inc(tot);                angle[tot].value:=arccot(x,y);                angle[tot].x:=x;                angle[tot].y:=y;                angle[tot].dis:=sqrt(x*x+y*y);        end;        qsort(2,n);//按角度为第一关键字、距离为第二关键字排序        up:=2;        stack[1]:=1;        stack[2]:=2;        for i:=3 to n do        begin                while judge(angle[stack[up-1]].x,angle[stack[up-1]].y,angle[stack[up]].x,angle[stack[up]].y,angle[i].x,angle[i].y)<0 do dec(up);//判断当前点是否满足要求                inc(up);                stack[up]:=i;//入栈        end;        ans:=0;        stack[up+1]:=stack[1];        for i:=1 to up do        ans:=ans+sqrt(sqr(angle[stack[i]].x-angle[stack[i+1]].x)+sqr(angle[stack[i]].y-angle[stack[i+1]].y));        writeln(ans:0:2);//统计凸包上两两相邻的点的距离,输出end.
原创粉丝点击