算法学习:计算几何旋转卡壳

【定义】

【对踵点】多边形上存在平行切线的两点

【多边形半径】多边形上任意两点的最大长度

 


【旋转卡壳】

 选取y轴上,最高和最低的两个点,令两条平行于x轴的线切过这两点

 然后我们开始让这两条线旋转

 当一条线首先和多边形上一条线段平行时,另外一条边也会停止旋转

 这个时候,就需要通过叉乘来判断现在取得对点是否符合要求

 即,拥有平行的切线

此处我们用另外一种方法来找到,当前点所对应的最远点(向量的证明还不会QAQ)

确定一条边,然后按逆时针求这个点和这条边组成的三角形的面积

当这个面积最大时,这个点就是最远点

(此处我们找的是,离这条线段最远的点)

 

 需要注意下最初比较选取时,各个值的赋值(我就因为这个浪费了两个小时QAQ)

l max_dis(P* p)
{
    int maxp = 1, minp = 1;
    ll  maxy =-1001, miny = 1001;
    for (int i = 1; i <=n; i++)
    {
        if (p[i].y > maxy) maxy = p[i].y, maxp = i;
        if (p[i].y < miny )miny = p[i].y, minp = i;
    }
    ll ans = max(dis(p[minp],p[maxp]),dis(p[(minp%n)+1],p[maxp]));
    for (int i = 1; i <=n; i++,minp=(minp+1>n)?1:(minp+1))
    {
        while (cross(p[(minp%n) + 1], p[(maxp % n)+1], p[minp]) > cross(p[(minp%n) + 1], p[maxp], p[minp]))
            maxp = (maxp+1) %n;
        ans = max(ans, dis(p[minp], p[maxp]));
        ans = max(ans, dis(p[(minp % n) +1], p[maxp]));
    }
    return ans;
}
View Code

 


模板题:

【POJ 2178】

 给定多边形,求多边形的半径

 

#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
#include<map>
#include<cmath>
#define ll int 
using namespace std;
const ll eps = 0;
const int MAXN = 50010;
const ll INF = (1<<31)-1;
const ll lim = 100010;
int n;
struct V
{
    ll x, y;
    V(ll a = 0, ll b = 0) :x(a), y(b) {}
};
typedef V P;
V    operator+(V a, V b) { return V(a.x + b.x, b.y + a.y); }
V    operator-(V a, V b) { return V(a.x - b.x, b.y - a.y); }
V    operator*(V a, ll b) { return V(a.x*b, a.y*b); }
V    operator*(ll a, V b) { return V(a*b.x, b.y*a); }
V    operator/(V a, ll b) { return V(a.x / b, a.y / b); }
V    operator/(ll a, V b) { return V(b.x / a, b.y / a); }
ll   operator^(V a, V b) { return a.x*b.x + a.y*b.y; }
bool operator<(V a, V b) { return (a.x == b.x) ? a.y < b.y : a.x < b.x; }
int sgn(ll x)
{
    return (x > eps) - (x < eps);
}
ll  cross(V a, V b)
{
    return a.x*b.y - b.x*a.y;
}
ll cross(P a, P b, P c)
{
    return cross(b - a, c - a);
}
ll dis(V a)
{
    return a ^ a;
}
ll dis(P a, P b)
{
    return (dis(b - a));
}
P ans[MAXN], s[MAXN];
P p[MAXN];
P* convex(P* l)
{
    
    sort(l+1, l+1+n);
    P tmp(lim, lim);
    int pos = 0;
    int top = 0;
    for (int i = 1; i <=n; i++)
        if (l[i] < tmp)
            tmp = l[i], pos = i;
    for (int i = pos, cnt_ = 0; cnt_ < n; cnt_++, i =(i+1>n)?1:i+1)
    {
        while (top >= 2 && sgn(cross(s[top-2], s[top-1], l[i])) <= 0)
            top--;
        s[top] = l[i]; top++;
        pos = i;
    }
    int cnt = 0;
    for (int i = 0; i < top; i++)
    {
        cnt++;
        ans[cnt] = s[i];
    }
    top = 0;
    for (int i = pos, cnt_ = 0; cnt_ < n; cnt_++, i = (i - 1<1)?n:i-1)
    {
        while (top >= 2 && sgn(cross(s[top - 2], s[top - 1], l[i])) <= 0)
            top--;
        s[top] = l[i]; top++;
        pos = i;
    }
    for (int i = 1; i + 1 < top; i++)
    {
        cnt++;
        ans[cnt] = s[i];
    }
    n = cnt;
    return ans;
}
ll max_dis(P* p)
{
    int maxp = 1, minp = 1;
    ll  maxy =-1001, miny = 1001;
    for (int i = 1; i <=n; i++)
    {
        if (p[i].y > maxy) maxy = p[i].y, maxp = i;
        if (p[i].y < miny )miny = p[i].y, minp = i;
    }
    ll ans = max(dis(p[minp],p[maxp]),dis(p[(minp%n)+1],p[maxp]));
    for (int i = 1; i <=n; i++,minp=(minp+1>n)?1:(minp+1))
    {
        while (cross(p[(minp%n) + 1], p[(maxp % n)+1], p[minp]) > cross(p[(minp%n) + 1], p[maxp], p[minp]))
            maxp = (maxp+1) %n;
        ans = max(ans, dis(p[minp], p[maxp]));
        ans = max(ans, dis(p[(minp % n) +1], p[maxp]));
    }
    return ans;
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        P tmp;
        scanf("%d%d", &tmp.x, &tmp.y);
        p[i] = tmp;
    }
    printf("%d", max_dis(convex(p)));
    return 0;
}
View Code

 

posted @ 2019-07-30 20:27  rentu  阅读(250)  评论(0编辑  收藏  举报