题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1348

凸包模板:

 

const int N =1010;
const double PI = 3.1415927;
double EPS=1e-10;
// 考虑误差的加法运算
double add(double a,double b)
{
    if(fabs(a+b)<EPS*(fabs(a)+fabs(b))) return 0;
    return a+b;
}
struct Point{
    double x,y;
    Point(){}
    Point(double x,double y):x(x),y(y){} // 构造函数,方便代码编写
    Point(const Point & p):x(p.x),y(p.y){}
    Point operator +(Point p){
        return Point(add(x,p.x), add(y,p.y));
    }
    Point operator-(Point p){
        return Point(add(x,-p.x),add(y,-p.y));
    }
    Point operator*(double d){
        return Point(x*d,y*d);
    }
    double operator*(Point p){  // 内积 点乘
        return add(x*p.x, y*p.y);
    }
    double operator^(Point p){//  外积 叉乘
        return add(x*p.y,-y*p.x);
    }
    friend ostream& operator<<(ostream& os,const Point& p ){
        os<<p.x<<" "<<p.y<<endl;
        return os;
    }
    friend istream& operator>>(istream& is, Point& rh) {// Point 不能是常量,是变量
        is>>rh.x>>rh.y;
        return is;
    }
    double dist(Point p){
        return sqrt( add( (x-p.x)*(x-p.x),(y-p.y)* (y-p.y) ) );
    }
};

Point List[N];   // 输入点集Q
Point stack[N];  // 栈从低到顶部包含了按逆时针方向排列在CH(Q)(凸包)中的各个顶点。
int top;   // 栈顶

bool cmp(Point a,Point b)
{
    if(a.y!= b.y)
        return a.y<b.y;
    else return a.x<b.x;
}
// 按极角排序,如果极角相等则按距离从小到大,sort是按从小到大排列的,故需对<符号重载
bool operator<(Point p1,Point p2)
    {
    double  tmp=(p1-List[0])^(p2-List[0]); //List[0]为基点
    if(tmp>0) return 1;
    else if(tmp==0 && p1.dist(List[0])< p2.dist(List[0])) return 1;
    else return 0;
    }

// 输入点集Q,并把最左下方的点放在 LIst[0],作为基点,
//并且进行极角排序,对sort(list+1,List+n) ,最大时间O(nlgn)
void init(int n)
{
    for(int i=1;i<n;i++)
        cin>>List[i];
    sort(List, List+n,cmp); // List[0] 存储的是 左下方的点
    sort(List+1,List+n);   // 对 List[1]~ List[n-1] 进行对 List[0]的极角排序
}
// 寻找凸包 graham 扫描法 时间O(n)
void graham(int n)
{
    if(n==1)
        {top=0;
        stack[0]=List[0];}
    if(n==2)
    {
        top=1;
        stack[0]=List[0];
        stack[1]=List[1];
    }
    if(n>2)
    {
        for(int i=0;i<=1;i++)  // 初始化栈,有p0,p1进栈
            stack[i]=List[i];
        top=1;
        for(int i=2;i<n;i++)
        {
            while(top>=1 && ((stack[top]-stack[top-1])^(List[i]-stack[top-1]))<=0) // 非左转
                top--; // 删除栈顶元素
            top++;
            stack[top]=List[i]; // 将i压入栈
        }
    }
}

 

 

 

hdu 1348 求凸包的周长 + 圆周长

http://acm.hdu.edu.cn/showproblem.php?pid=1348

代码如下:

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <vector>
#include <set>
#include <math.h>
#include <cmath>
#include <map>
#include <queue>

using namespace std;
typedef long long ll;

const int N =1010;
const double PI = 3.1415927;
double EPS=1e-10;
// 考虑误差的加法运算
double add(double a,double b)
{
    if(fabs(a+b)<EPS*(fabs(a)+fabs(b))) return 0;
    return a+b;
}
struct Point{
    double x,y;
    Point(){}
    Point(double x,double y):x(x),y(y){} // 构造函数,方便代码编写
    Point(const Point & p):x(p.x),y(p.y){}
    Point operator +(Point p){
        return Point(add(x,p.x), add(y,p.y));
    }
    Point operator-(Point p){
        return Point(add(x,-p.x),add(y,-p.y));
    }
    Point operator*(double d){
        return Point(x*d,y*d);
    }
    double operator*(Point p){  // 内积 点乘
        return add(x*p.x, y*p.y);
    }
    double operator^(Point p){//  外积 叉乘
        return add(x*p.y,-y*p.x);
    }
    friend ostream& operator<<(ostream& os,const Point& p ){
        os<<p.x<<" "<<p.y<<endl;
        return os;
    }
    friend istream& operator>>(istream& is, Point& rh) {// Point 不能是常量,是变量
        is>>rh.x>>rh.y;
        return is;
    }
    double dist(Point p){
        return sqrt( add( (x-p.x)*(x-p.x),(y-p.y)* (y-p.y) ) );
    }
};

Point List[N];   // 输入点集Q
Point stack[N];  // 栈从低到顶部包含了按逆时针方向排列在CH(Q)(凸包)中的各个顶点。
int top;   // 栈顶

bool cmp(Point a,Point b)
{
    if(a.y!= b.y)
        return a.y<b.y;
    else return a.x<b.x;
}
// 按极角排序,如果极角相等则按距离从小到大,sort是按从小到大排列的,故需对<符号重载
bool operator<(Point p1,Point p2)
    {
    double  tmp=(p1-List[0])^(p2-List[0]); //List[0]为基点
    if(tmp>0) return 1;
    else if(tmp==0 && p1.dist(List[0])< p2.dist(List[0])) return 1;
    else return 0;
    }

// 输入点集Q,并把最左下方的点放在 LIst[0],作为基点,
//并且进行极角排序,对sort(list+1,List+n) ,最大时间O(nlgn)
void init(int n)
{
    for(int i=0;i<n;i++)
        cin>>List[i];
    sort(List, List+n,cmp); // List[0] 存储的是 左下方的点
    sort(List+1,List+n);   // 对 List[1]~ List[n-1] 进行对 List[0]的极角排序
}
// 寻找凸包 graham 扫描法 时间O(n)
void graham(int n)
{
    if(n==1)
        {top=0;
        stack[0]=List[0];}
    if(n==2)
    {
        top=1;
        stack[0]=List[0];
        stack[1]=List[1];
    }
    if(n>2)
    {
        for(int i=0;i<=1;i++)  // 初始化栈,有p0,p1进栈
            stack[i]=List[i];
        top=1;
        for(int i=2;i<n;i++)
        {
            while(top>=1 && ((stack[top]-stack[top-1])^(List[i]-stack[top-1]))<=0) // 非左转
                top--; // 删除栈顶元素
            top++;
            stack[top]=List[i]; // 将i压入栈
        }
    }
}
int main()
{
    int T,count=0,n;
    double r;
    cin>>T;
    while(T--)
    {
        if(count) cout<<endl;
        count=1;
        cin>>n>>r;
        init(n);
        graham(n);
        double ans=0;
        for(int i=0;i<top;i++)
            ans+=stack[i].dist(stack[i+1]);
        ans+=stack[top].dist(stack[0]);
        ans+=2*PI*r;
        printf("%.0lf\n",ans);
    }
    return 0;
}