题目链接: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; }