讲解见:http://www.cnblogs.com/Booble/archive/2011/04/03/2004865.html
实现:(在原有求凸包的基础上增加即可)
double cross(Pt a,Pt b,Pt c)//求叉积
{
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
double dist2(Pt a,Pt b)//求距离
{
Pt x=a-b;
return (x.norm());//因为本题只要求求距离的平方所以没有开方
}
double rotating_calipers(Poly p)//旋转卡壳
{
int j=1,n=p.pts.size();p.pts.push_back(p.pts[0]);
double ans=0;
for(int i=0;i<n;i++)
{
while(cross(p.pts[i],p.pts[i+1],p.pts[j])<cross(p.pts[i],p.pts[i+1],p.pts[j+1]))
j=(j+1)%n;
ans=max(ans,max(dist2(p.pts[i],p.pts[j]),dist2(p.pts[i+1],p.pts[j+1])));
}
return ans;
}
POJ2187:(跑得比暴力枚举O(n^2)还慢是什么鬼2333)
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include<iostream>
using namespace std;
const int MAXN = 50005;
const double EPS = 1e-8;
// 带误差比较
inline bool dcmp(double x, double y = 0)
{
return fabs(x - y) <= EPS;
}
/*
* 向量(Vector)或点
*
* 使用原点到一个点 (x, y) 的有向线段表示向量
* 从点 A 到点 B 的向量表示为 A - B
*/
typedef struct Vec
{
double x, y;
Vec(double x = 0, double y = 0) : x(x), y(y) {}
// 相加
Vec operator+(const Vec &v) const
{
return Vec(x + v.x, y + v.y);
}
// 相减
Vec operator-(const Vec &v) const
{
return Vec(x - v.x, y - v.y);
}
// 数乘(伸长、缩短)
Vec operator*(double d) const
{
return Vec(x * d, y * d);
}
Vec operator/(const double d) const
{
return Vec(x / d, y / d);
}
// 范数,用来比较长度,等于长度的平方
double norm() const
{
return x * x + y * y;
}
} Pt;
// 点乘
double dot(const Vec &a, const Vec &b)
{
return a.x * b.x + a.y * b.y;
}
// 叉乘
double cross(const Vec &a, const Vec &b)
{
return a.x * b.y - a.y * b.x;
}
// 线段(Segment),用两个点表示
struct Seg
{
Pt a, b;
Seg(const Pt &a, const Pt &b) : a(a), b(b) {}
// 线段包含点(点在线段上)
bool include(const Pt &p)
{
// PA × PB = 0:PA 与 PB 共线,即点在线段所在的直线上
// PA · PB = 0:PA 与 PB 方向不同(A 和 B 分别在 P 的两边),如果 PA · PB = 0 则 P = A 或 P = B
return dcmp(cross(a - p, b - p)) && dot(a - p, b - p) <= 0;
}
};
// 直线,用两个点表示
struct Line
{
Pt a, b;
Line() {} // 提供一个不需要参数的构造函数
Line(const Pt &a, const Pt &b) : a(a), b(b) {}
bool include(const Pt &p) const
{
return dcmp(cross(a - p, b - p));
}
// 两直线关系(交点个数)
// 0 表示平行(无交点)
// 1 表示相交(一个交点)
// -1 表示重合(无数个交点)
static int relation(const Line &a, const Line &b)
{
if (a.include(b.a) && a.include(b.b)) return -1;
else if (dcmp(cross(a.b - a.a, b.b - b.a))) return 0;
else return 1;
}
// 求两直线交点(需要保证两直线有交点)
static Pt intersect(const Line &a, const Line &b)
{
double s1 = cross(b.a - a.a, b.b - a.a), s2 = cross(b.b - a.b, b.a - a.b);
return a.a + (a.b - a.a) * s1 / (s1 + s2);
}
};
// 求凸包用的点
int n;
Pt a[MAXN + 1];
// 凸包极角排序的比较函数
inline bool compare(const Pt &a, const Pt &b)
{
// 两个向量
Vec va = a - ::a[1], vb = b - ::a[1];
double t = cross(va, vb);
if (!dcmp(t)) return t > 0; // OA -> OB 是逆时针,则 A 极角序在先
else return va.norm() < vb.norm(); // norm 较小的长度较小
}
struct Poly
{
std::vector<Pt> pts;
// 求凸包(Convex),结果储存在自身 pts 中
void convex()
{
// 找出最左下角的点
int id = 1;
for (int i = 1; i <= n; i++)
{
if (a[i].x < a[id].x || (a[i].x == a[id].x && a[i].y < a[id].y)) id = i;
}
if (id != 1) std::swap(a[1], a[id]);
// 排序
std::sort(a + 2, a + n + 1, &compare);
// 极角序扫描
pts.push_back(a[1]);
for (int i = 2; i <= n; i++)
{
// 比较,如果最后一个点需要被删掉则弹出(pop_back)
while (pts.size() >= 2 && cross(a[i] - pts[pts.size() - 2], pts.back() - pts[pts.size() - 2]) >= 0) pts.pop_back();
pts.push_back(a[i]);
}
}
};
double cross(Pt a,Pt b,Pt c)
{
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
//double cross(const Vec &a, const Vec &b)
//{
// return a.x * b.y - a.y * b.x;
//}
double dist2(Pt a,Pt b)
{
Pt x=a-b;
return (x.norm());//因为本题只要求求距离的平方所以没有开方
}
double rotating_calipers(Poly p)
{
int j=1,n=p.pts.size();p.pts.push_back(p.pts[0]);
double ans=0;
for(int i=0;i<n;i++)
{
while(cross(p.pts[i],p.pts[i+1],p.pts[j])<cross(p.pts[i],p.pts[i+1],p.pts[j+1]))
j=(j+1)%n;
ans=max(ans,max(dist2(p.pts[i],p.pts[j]),dist2(p.pts[i+1],p.pts[j+1])));
}
return ans;
}
int main()
{
int i,j;
cin>>n;
for(i=1;i<=n;i++){
scanf("%lf%lf",&a[i].x,&a[i].y);
}
Poly p;p.convex();
cout<<(int)rotating_calipers(p)<<endl;
return 0;
}
1731



被折叠的 条评论
为什么被折叠?



