Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 31419 | Accepted: 10619 |
Description
Input
Output
Sample Input
9 100 200 400 300 400 300 300 400 300 400 400 500 400 500 200 350 200 200 200
Sample Output
1628
Hint
Source
附:
针对上面的公式(1)copy一个证明:http://blog.sina.com.cn/s/blog_687916bf0100jq9g.html
证明如下:假如顺时针给出四个点A、B、C、D。组成了凸四边形ABCD。我们不妨过A点作AE垂直于AB,同时过A点再作AF垂直于AD,过B点 作BG、BH分别垂直于AB、BC。连结EG,垂线段的长度为L,过A点以AE为半径作一段弧连到AF,同理,使GH成为一段弧。此时 EG=AB(边),AB段城墙的最小值为EF+弧EF+弧GH=AB+弧EF+弧GH。对所有点进行同样的操作后,可知城墙的最小值=四边形的周长+相应 顶点的弧长(半径都为L)之和。
下面证明这些顶点弧长组成一个圆。依然以前面的四边形为例。A、B、C、D四顶点各成周角,总和为360*4=1440度,四边形内角和为360度,每个顶点作两条垂线,总角度为4*2*90=720度,所以总圆周角为1440-360-720=360度,刚好组成圆。
所以四边形ABCD的围墙最短= 四边形的周长+圆周长。
推广到任意多边形,用同样的方法,城墙最短=凸包的周长 + 以L为半径的圆的周长。
首先,我们得出城墙最短=凸包的周长 + 相应顶点的弧长(半径都为L)之和。
再证明 相应顶点的弧长(半径都为L)之和=以L为半径的圆的周长。
事实上,设凸包顶点为n,n个顶点组成n个周角,角度为360*n=2*180*n,凸包的内角和为180*(n-2),作了2*n条垂线,和为2*n*90=180*n,所以总圆周角为2*180*n-180*(n-2)-180*n=360,组成圆。
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <cmath> #define pi 3.141592653 #define maxn 1010 #define eps 1e-8 using namespace std; int Stack[maxn]; int top ; struct Point { int x; int y; Point() {} } List[maxn]; int cross(Point p0,Point p1,Point p2) //计算叉积 p0p1 X p0p2 { return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x); } double dist(Point p1,Point p2) //计算 p1p2的 距离 { return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); } bool cmp(Point p1,Point p2) { int tmp = cross(List[0],p1,p2); if(tmp >0) return true; else if(tmp== 0 && dist(List[0],p1) < dist(List[0],p2)) return true; else return false; } void graham(int n) { // scanf("%d %d",&List[0].x,&List[0].y); Point p0; int k=0; p0 = List[0]; for(int i=1; i<n; i++) { // scanf("%d %d",&List[i].x,&List[i].y); if( (p0.y>List[i].y) || ((p0.y==List[i].y)&&(p0.x>List[i].x)) ) { p0 = List[i]; k = i; } } List[k] = List[0]; List[0] = p0; sort(List+1,List+n,cmp); if(n == 1) { top = 0; Stack[0] = 0; } if(n == 2) { top = 1; Stack[0] = 0; Stack[1] = 1; } if(n > 2) { Stack[0] = 0; Stack[1] = 1; top = 1; for(int i=2; i<n; i++) { while(top > 0 && cross(List[Stack[top-1]],List[Stack[top]],List[i])<=0) top--; top++; Stack[top] = i; } } } int main() { // freopen("in.txt","r",stdin); int n,l; while(~scanf("%d %d",&n,&l)) { memset(List,0,sizeof(List)); memset(Stack,0,sizeof(Stack)); // init(n); for(int i=0;i<n;i++) { scanf("%d %d",&List[i].x,&List[i].y);; } graham(n); double sum = 0; for(int i=0; i<top; i++) { sum += dist(List[Stack[i]],List[Stack[i+1]]); } sum += dist(List[Stack[0]],List[Stack[top]]); sum = sum + 2 * pi * l; printf("%d\n",(int)(sum+0.5)); } }