标签:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 33446 | Accepted: 11376 |
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
据题意可得: 所求结果为凸包周长+ 2*PI* L ;
转个分析:
证明如下:假如顺时针给出四个点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 <cmath> #include <cstdio> #define PI acos(-1.0) #define MAXN 1001 #include <iostream> #include <algorithm> using namespace std; struct point { int x, y; } ; point list[MAXN]; int stack[MAXN], top; 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 dis(point p1, point p2) { 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&& dis(list[0], p1) < dis(list[0], p2)) return true; else return false; } void init(int n) //找出左下角的点放在list[0] 中 ; { point fv; scanf("%d%d", &list[0].x, &list[0].y); fv.x= list[0].x; fv.y=list[0].y; int k=0; for(int i=1; i<n; i++) { scanf("%d%d", &list[i].x, &list[i].y); if( (fv.y >list[i].y) || (fv.y==list[i].y && fv.x>list[i].x)) { fv.x= list[i].x; fv.y =list[i].y; k=i; } } list[k]= list[0]; list[0]=fv; sort(list+1, list+n, cmp) ; } void graham(int n) { if(n==1) {top=0; stack[0]=0;} if(n==2) {top=1; stack[0]=0; stack[1]=1;} if(n >2) { for(int i=1; i<=1; i++) stack[i]=i; 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() { int N, L; while(scanf("%d%d", &N, &L) != EOF) { init(N); graham(N); double res= 0; for(int i=0; i<top; i++) res+= dis(list[stack[i]], list[stack[i+1]]); res +=dis(list[stack[0]], list[stack[top]]); res += 2*PI*L; //printf("%d\n", (int)(res+0.5)); printf("%.lf\n", res ); } return 0; }
标签:
原文地址:http://www.cnblogs.com/fengshun/p/5350115.html