POJ 1113 Wall(凸包周长)

题目链接:POJ 1113 Wal

所求周长 = 凸包周长 + 半径为L的圆的周长。

这个我不会证明,我是画了一个圆的城堡,画了一个正方形的城堡,这两种都是满足上边的公式的,然后我认为这是两个极限,中间的都满足。或许三角形城堡才是一个极限吧。

我自己写了一个卷包裹法,然后又用了一下刘汝佳的模版,速度差了一半,算法的力量真的好强大。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>

using namespace std;

const double eps = 1e-10;
const int MAX_N = 1000 + 10;
const double PI = acos(-1);

struct Point
{
	int x, y;
	Point(int x=0, int y=0):x(x),y(y) { }
};

typedef Point Vector;

Point p[MAX_N];

Vector operator + (const Vector& A, const Vector& B)
{
    return Vector(A.x+B.x, A.y+B.y);
}

Vector operator - (const Point& A, const Point& B)
{
    return Vector(A.x-B.x, A.y-B.y);
}

Vector operator * (const Vector& A, double p)
{
    return Vector(A.x*p, A.y*p);
}

bool operator < (const Point& a, const Point& b)
{
	return a.x < b.x || (a.x == b.x && a.y < b.y);
}

int dcmp(double x)
{
    if(fabs(x) < eps)
        return 0;
    else
        return x < 0 ? -1 : 1;
}

bool operator == (const Point& a, const Point &b)
{
	return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}

double Cross(const Vector& A, const Vector& B)
{
    return A.x*B.y - A.y*B.x;
}

double Dot(const Vector& A, const Vector& B)
{
    return A.x*B.x + A.y*B.y;
}

double Length(const Vector& A)
{
    return sqrt(Dot(A, A));
}
double dist(int a, int b)
{
    double x1, x2, y1, y2, res;
    x1 = p[a].x, x2 = p[b].x, y1 = p[a].y, y2 = p[b].y;
    res = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    return res;
}
int path[MAX_N];

int main()
{
    //freopen("in.txt", "r", stdin);
    int n, l;
    scanf("%d%d", &n, &l);
    int _minX = 10010, _minY = 10010, _start, _beg, _end, _size = 0;
    double dis = 0.0;
    for(int i = 0; i < n; i++)
    {
        scanf("%d%d", &p[i].x, &p[i].y);
        if(_minY > p[i].y || (_minY == p[i].y && _minX > p[i].x))
        {
            _start = i;
            _minY = p[i].y;
            _minX = p[i].x;
        }
    }
    _beg = _start;
    path[_size++] = _start;
    while(true)
    {
        _end = 0;
        for(int i = 0; i < n; i++)
        {
            if(Cross(p[i] - p[_beg], p[_end] - p[_beg]) > 0 ||
               ((Cross(p[i] - p[_beg], p[_end] - p[_beg]) == 0) &&
                dcmp(Length(p[i] - p[_beg]) - Length(p[_end] - p[_beg])) > 0))
                _end = i;
        }
        if(_end == _start) //卷到起点了
            break;
        path[_size++] = _beg = _end;
    }
    for(int i = 0; i < _size - 1; i++)
        dis += dist(path[i], path[i + 1]);
    dis += dist(path[_size - 1], path[0]);
    dis += 2 * PI * l;
    printf("%.0f\n", dis);
    return 0;
}

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

const double eps = 1e-10;
const double PI = acos(-1);
const int MAX_N = 1000 + 10;

struct Point
{
	int x, y;
	Point(int x=0, int y=0):x(x),y(y) { }
};

typedef Point Vector;

Point p[MAX_N];

Vector operator + (const Vector& A, const Vector& B)
{
    return Vector(A.x+B.x, A.y+B.y);
}

Vector operator - (const Point& A, const Point& B)
{
    return Vector(A.x-B.x, A.y-B.y);
}

Vector operator * (const Vector& A, double p)
{
    return Vector(A.x*p, A.y*p);
}

bool operator < (const Point& a, const Point& b)
{
	return a.x < b.x || (a.x == b.x && a.y < b.y);
}

int dcmp(double x)
{
    if(fabs(x) < eps)
        return 0;
    else
        return x < 0 ? -1 : 1;
}

bool operator == (const Point& a, const Point &b)
{
	return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}

double Cross(const Vector& A, const Vector& B)
{
    return A.x*B.y - A.y*B.x;
}

double Dot(const Vector& A, const Vector& B)
{
    return A.x*B.x + A.y*B.y;
}

double Length(const Vector& A)
{
    return sqrt(Dot(A, A));
}

// 点集凸包
// 如果不希望在凸包的边上有输入点,把两个 <= 改成 <
// 如果不介意点集被修改,可以改成传递引用
vector<Point> ConvexHull(vector<Point> p)
{
  // 预处理,删除重复点
      sort(p.begin(), p.end());
      p.erase(unique(p.begin(), p.end()), p.end());

      int n = p.size();
      int m = 0;
      vector<Point> ch(n+1);
      for(int i = 0; i < n; i++) {
        while(m > 1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;
        ch[m++] = p[i];
      }
      int k = m;
      for(int i = n-2; i >= 0; i--) {
        while(m > k && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;
        ch[m++] = p[i];
      }
      if(n > 1) m--;
      ch.resize(m);
      return ch;
}

// 多边形的有向面积
double PolygonArea(vector<Point> p)
{
      double area = 0;
      int n = p.size();
      for(int i = 1; i < n-1; i++)
        area += Cross(p[i]-p[0], p[i+1]-p[0]);
      return area/2;
}
int n, l;

double get_dis(vector<Point> p)
{
    double dis = 0;
    int n = p.size();
    double x1, x2, y1, y2;
    for(int i = 0; i < n - 1; i++)
    {
        x1 = p[i].x, x2 = p[i + 1].x, y1 = p[i].y, y2 = p[i + 1].y;
        dis += sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }
    x1 = p[n - 1].x, x2 = p[0].x, y1 = p[n - 1].y, y2 = p[0].y;
    dis += sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    dis += 2 * PI * l;
    return dis;
}


double torad(double deg)
{
    return deg/180 * PI;
}
Vector Rotate(const Vector& A, double rad)
{
    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}
int main()
{
    scanf("%d%d", &n, &l);
    vector <Point> P;
    int x, y;
    for(int i = 0; i < n; i++)
    {
        scanf("%d%d", &x, &y);
        P.push_back(Point(x, y));
    }
    printf("%.0f\n", get_dis(ConvexHull(P)));
    return 0;
}


你可能感兴趣的:(POJ 1113 Wall(凸包周长))