Once upon a time there was a greedy King who ordered hischief Architect to build a wall around the King's castle. The King was sogreedy, that he would not listen to his Architect's proposals to build abeautiful brick wall with a perfect shape and nice tall towers. Instead, heordered to build the wall around the whole castle using the least amount ofstone and labor, but demanded that the wall should not come closer to thecastle than a certain distance. If the King finds that the Architect has usedmore resources to build the wall than it was absolutely necessary to satisfythose requirements, then the Architect will loose his head. Moreover, hedemanded Architect to introduce at once a plan of the wall listing the exactamount of resources that are needed to build the wall.
Your task is to help poor Architect to save his head, by writing a program thatwill find the minimum possible length of the wall that he could build aroundthe castle to satisfy King's requirements.
The task is somewhat simplified by the fact, that the King's castle has apolygonal shape and is situated on a flat ground. The Architect has alreadyestablished a Cartesian coordinate system and has precisely measured thecoordinates of all castle's vertices in feet.
Input
Input contains several test cases. The first line of each case contains twointeger numbers N and L separated by a space. N (3 <= N <= 1000) is thenumber of vertices in the King's castle, and L (1 <= L <= 1000) is theminimal number of feet that King allows for the wall to come close to thecastle.
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. Allvertices are different and the sides of the castle do not intersect anywhereexcept for vertices.
Process to end of file.
Output
For each case in the input, write to the output file the single number thatrepresents the minimal possible length of the wall in feet that could be builtaround the castle to satisfy King's requirements. You must present the integernumber 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 8inches (1 foot is equal to 12 inches), since the King will not tolerate largererror 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
题意:
求最小凸包的周长,注意这题要求凸包的外面一层的周长,长度为凸包周长加上一个圆周(证明方法可用多边形内角和和补角公式证明)。
求最小凸包方法如下:找到y最小,y相同x最大的点为新坐标系的原点。将点按极角大小排序(可利用向量叉乘来实现)。在这种排列的前提下可得:每条边若在前一条边的基础上左拐形成凸角,右拐形成凹角。将点依次入栈,入栈前保证栈顶元素与新加入点练成的边“左拐”,否则不断出栈知道找到满足条件的点,或栈中只剩原点。最后留在栈中的点,即为构成凸包的点,依次算出边长即可。
排序复杂度为O(nlogn),用栈筛选凸包复杂度为O(n),总复杂度为O(nlogn).
#include <iostream>
#include <cmath>
#include <cstdio>
#include <stack>
#include <algorithm>
#include <vector>
using namespace std;
const double exps=1e-9; //double比较最好定义一个无限小,当差值小于无限小时认为相等
const double PI=3.141592653589793238462643383279;
struct Point{ // 点类
double x,y;
Point(double xx=0,double yy=0):x(xx),y(yy){}
friend double dis(const Point &a,const Point &b){//两点距
return sqrt( (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) );
}
};
struct Vec{ //向量类
double x,y;
Vec(){}
Vec(const Point &a,const Point &b){ //有两点构造一个响亮
x=a.x-b.x;
y=a.y-b.y;
}
friend double operator*(const Vec& a,const Vec& b){//重载向量叉乘,返回标量值
return a.x*b.y-a.y*b.x;
}
};
vector<Point> p;//存点的数组
bool cmp(const Point &a,const Point& b){//极角排序,极角相等按原点距排
Point o={0.0,0.0};
Vec x={a,o},y={b,o};
return x*y>exps || (fabs(x*y)<exps && dis(a,o)<dis(b,o));
}
int main()
{
int n,i;
double l;
Point tem;
while(~scanf("%d%lf",&n,&l)){
p.clear();
int k=0;
for(i=0;i<n;++i){
double a,b;
scanf("%lf%lf",&a,&b);
p.push_back(Point{a,b});
if(p[i].y<p[k].y || (p[i].y==p[k].y && p[i].x>p[k].x))
k=i;//最下右点,满足左拐检验法
}
Point o={0.0,0.0};//原点
tem=p[k];
p.erase(p.begin()+k);
for(int i=0;i<p.size();++i){
p[i].x-=tem.x;
p[i].y-=tem.y;
}
sort(p.begin(),p.end(),cmp);
stack<Point> st;//筛选栈
st.push(o);
for(int i=0;i<p.size();++i){
while(st.size()>1){//保证满足左拐
Point now=st.top();
st.pop();
Point pre=st.top();
st.push(now);
if(Vec{now,pre}*Vec{p[i],now}>=0.0){
st.push(p[i]);
break;
}
st.pop();
}
if(st.size()==1) st.push(p[i]);//只剩原点,没有边,直接进栈
}
double ans=0.0;
tem=st.top();
ans+=dis(tem,o);//统计周长,栈中剩余点即为凸包的构成点
st.pop();
while(!st.empty()){
Point t=st.top();
ans+=dis(tem,t);
tem=t;
st.pop();
}