poj1113Wall(凸包周长计算):http://poj.org/problem?id=1113
题目描述:
Wall
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 35235 | Accepted: 11996 |
Description
Once upon a time there was a greedy King who ordered his chief Architect to build a wall around the King's castle. The King was so greedy, that he would not listen to his Architect's proposals to build a beautiful brick wall with a perfect shape and nice tall towers. Instead, he ordered to build the wall around the whole castle using the least amount of stone and labor, but demanded that the wall should not come closer to the castle than a certain distance. If the King finds that the Architect has used more resources to build the wall than it was absolutely necessary to satisfy those requirements, then the Architect will loose his head. Moreover, he demanded Architect to introduce at once a plan of the wall listing the exact amount of resources that are needed to build the wall.
Your task is to help poor Architect to save his head, by writing a program that will find the minimum possible length of the wall that he could build around the castle to satisfy King's requirements.
The task is somewhat simplified by the fact, that the King's castle has a polygonal shape and is situated on a flat ground. The Architect has already established a Cartesian coordinate system and has precisely measured the coordinates of all castle's vertices in feet.
![](https://i-blog.csdnimg.cn/blog_migrate/795547457e5e67245c9908aff158362e.gif)
Your task is to help poor Architect to save his head, by writing a program that will find the minimum possible length of the wall that he could build around the castle to satisfy King's requirements.
The task is somewhat simplified by the fact, that the King's castle has a polygonal shape and is situated on a flat ground. The Architect has already established a Cartesian coordinate system and has precisely measured the coordinates of all castle's vertices in feet.
Input
The first line of the input file contains two integer numbers N and L separated by a space. N (3 <= N <= 1000) is the number of vertices in the King's castle, and L (1 <= L <= 1000) is the minimal number of feet that King allows for the wall to come close to the castle.
Next N lines describe coordinates of castle's vertices in a clockwise order. Each line contains two integer numbers Xi and Yi separated by a space (-10000 <= Xi, Yi <= 10000) that represent the coordinates of ith vertex. All vertices are different and the sides of the castle do not intersect anywhere except for vertices.
Next N lines describe coordinates of castle's vertices in a clockwise order. Each line contains two integer numbers Xi and Yi separated by a space (-10000 <= Xi, Yi <= 10000) that represent the coordinates of ith vertex. All vertices are different and the sides of the castle do not intersect anywhere except for vertices.
Output
Write to the output file the single number that represents the minimal possible length of the wall in feet that could be built around the castle to satisfy King's requirements. You must present the integer number of feet to the King, because the floating numbers are not invented yet. However, you must round the result in such a way, that it is accurate to 8 inches (1 foot is equal to 12 inches), since the King will not tolerate larger error in the estimates.
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
结果四舍五入就可以了
题目大意:
求可以把凸包建筑围起来的,且和凸包相距最小L的墙的长度。
题目分析:
本题比较容易想到凸包问题,但又不是直接求解凸包,可以证明:最短的墙壁周长等于凸包长度再加上一个半径为L的圆的周长。
简略证明如下:
若求围住城堡所需的最小长度,即是求凸包长度;但由于建造的围墙距离城堡还有一个距离L,故要求的周长还要比已经求出来的凸包多了几段圆弧,而所有的圆弧的圆心角和为360度,则可以用凸包的方法求解。
如下图:
代码实现:
方法一:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define Maxsize 1000
using namespace std;
struct point
{
int x,y;
}x[Maxsize];
bool cmp(point a,point b)
{
return (a.y<b.y||a.y==b.y && a.x<b.x);
}
int n,l,ans[Maxsize],cnt,sta[Maxsize],tail;
bool CrossLeft(point p1,point p2,point p3)///判断是否严格左转,共线不算左转
{
return ((p3.x-p1.x)*(p2.y-p1.y)-(p2.x-p1.x)*(p3.y-p1.y))<0;
}
void Jarvis()
{
tail=cnt=0;
sort(x,x+n,cmp);
sta[tail++]=0;
sta[tail++]=1;
for(int i=2;i<n;i++)
{
while(tail>1 && !CrossLeft(x[sta[tail-1]],x[sta[tail-2]],x[i]))
tail--;
sta[tail++]=i;
}
for(int i=0;i<tail;i++)
{
ans[cnt++]=sta[i];
}
tail=0;
sta[tail++]=n-1;
sta[tail++]=n-2;
for(int i=n-3;i>=0;i--)
{
while(tail>1 && !CrossLeft(x[sta[tail-1]],x[sta[tail-2]],x[i]))
tail--;
sta[tail++]=i;
}
for(int i=0;i<tail;i++)
{
ans[cnt++]=sta[i];
}
}
int main()
{
while(scanf("%d%d",&n,&l)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%d%d",&x[i].x,&x[i].y);
}
Jarvis();
double re=4*acos(0.0)*l;///求半径为l的圆的周长,cos(pi/2)=0,利用反三角函数
for(int i=0;i<cnt-1;i++)
{
re+=sqrt((x[ans[i]].x-x[ans[i+1]].x)*(x[ans[i]].x-x[ans[i+1]].x)+1.0*(x[ans[i]].y-x[ans[i+1]].y)*(x[ans[i]].y-x[ans[i+1]].y));
}
printf("%.0f\n",re);
}
return 0;
}
方法二:
利用Graham-Scan算法
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <cstdlib>
#include <stdio.h>
using namespace std;
const double eps = 1e-8;
const double PI = acos(-1.0);
const int MAXN = 1010;
int sgn(double x)
{
if (fabs(x) < eps)return 0;
if (x < 0)return -1;
else return 1;
}
struct Point
{
int x, y;
Point() {}
Point(int _x, int _y)
{
x = _x;
y = _y;
}
Point operator -(const Point &b)const
{
return Point(x - b.x, y - b.y);
}
double operator ^(const Point &b)const
{
return x*b.y - y*b.x;
}
double operator *(const Point &b)const
{
return x*b.x + y*b.y;
}
void transXY(double B)
{
double tx = x, ty = y;
x = tx*cos(B) - ty*sin(B);
y = tx*sin(B) + ty*cos(B);
}
};
Point llist[MAXN];
int Stack[MAXN], top;
///*两点间距离
double dist(Point a, Point b)
{
return sqrt((a - b)*(a - b));
}
///相对于list[0]的极角排序
bool _cmp(Point p1, Point p2)
{
double tmp = (p1 - llist[0]) ^ (p2 - llist[0]);
if (sgn(tmp) > 0)return true;
else if (sgn(tmp) == 0 && sgn(dist(p1, llist[0]) - dist(p2, llist[0])) <= 0)
return true;
else return false;
}
void Graham(int n)
{
Point p0;
int k = 0;
p0 = llist[0];
///找最下边的一个点
for (int i = 1; i < n; i++)
{
if ((p0.y > llist[i].y) || (p0.y == llist[i].y && p0.x > llist[i].x))
{
p0 = llist[i];
k = i;
}
}
Point kkkkk;
kkkkk=llist[k];
llist[k]=llist[0];
llist[0]=kkkkk;
sort(llist + 1, llist + n, _cmp);
if (n == 1)
{
top = 1;
Stack[0] = 0;
return;
}
if (n == 2)
{
top = 2;
Stack[0] = 0;
Stack[1] = 1;
return;
}
Stack[0] = 0;
Stack[1] = 1;
top = 2;
for (int i = 2; i < n; i++)
{
while (top > 1 &&
sgn((llist[Stack[top - 1]] - llist[Stack[top - 2]]) ^ (llist[i] - llist[Stack[top - 2]])) <=0)
top--;
Stack[top++] = i;
}
}
int main()
{
int nn, l;
double result;
while (cin >> nn >> l)
{
memset(llist,0,sizeof(llist));
for (int i = 0; i < nn; i++)
cin >> llist[i].x >> llist[i].y;
Graham(nn);
result= 0;
for (int i = 0; i < top-1; i++)
{
result += dist(llist[Stack[i]], llist[Stack[i+1]]);
}
result+=dist(llist[Stack[0]],llist[Stack[top-1]]);
result += PI*l*2;
int res = (int)(result+0.5);
cout << res << endl;
}
}