【计算几何】计算几何复习

点,线,面,形基本关系,点积叉积的理解

poj2318 TOYS

/****************************\
 * @prob: poj2318 TOYS      *
 * @auth: Wang Junji        *
 * @stat: Accepted.         *
 * @date: June. 25th, 2012  *
 * @memo: 点和直线位置关系    *
\****************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 5010;
int cnt[maxN], lower[maxN], upper[maxN], n, m, X0, Y0, X1, Y1;

inline int Find(int x, int y)
{
    int L = 0, R = n;
    while (L < R)
    {
        int Mid = (L + R) >> 1;
        double __x = (upper[Mid] - lower[Mid]) / double(Y1 - Y0) * (y - Y0) + lower[Mid];
        if (__x < x) L = Mid + 1;
        else R = Mid;
    } /* while */
    return R - 1;
} /* Find */

int main()
{
    freopen("toys.in" , "r", stdin );
    freopen("toys.out", "w", stdout);
    while (~scanf("%d%d%d%d%d%d", &n, &m, &X0, &Y1, &X1, &Y0) && n)
    {
        ++n; upper[0] = lower[0] = X0;
        for (int i = 1; i < n; ++i)
            scanf("%d%d", upper + i, lower + i);
        lower[n] = upper[n] = X1;
        memset(cnt, 0, sizeof cnt);
        while (m--)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            ++cnt[Find(x, y)];
        } /* while */
        for (int i = 0; i < n; ++i)
            printf("%d: %d\n", i, cnt[i]);
        puts("");
    } /* while */
    return 0;
} /* main */

/*

用二分查找每个玩具所对应的分区即可。

*/
poj2398 Toy Storage

/*******************************\
 * @prob: poj2398 Toy Storage  *
 * @auth: Wang Junji           *
 * @stat: Accepted.            *
 * @date: June. 25th, 2012     *
 * @memo: 点和直线位置关系       *
\*******************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 1010;
int has[maxN], cnt[maxN], lower[maxN], upper[maxN], n, m, X0, Y0, X1, Y1;

inline int Find(int x, int y)
{
    int L = 0, R = n;
    while (L < R)
    {
        int Mid = (L + R) >> 1;
        double __x = (upper[Mid] - lower[Mid]) / double(Y1 - Y0) * (y - Y0) + lower[Mid];
        if (__x < x) L = Mid + 1;
        else R = Mid;
    } /* while */
    return R - 1;
} /* Find */

int main()
{
    freopen("Toy_Storage.in" , "r", stdin );
    freopen("Toy_Storage.out", "w", stdout);
    while (~scanf("%d%d%d%d%d%d", &n, &m, &X0, &Y1, &X1, &Y0) && n)
    {
        ++n; upper[0] = lower[0] = X0;
        for (int i = 1; i < n; ++i)
            scanf("%d%d", upper + i, lower + i);
        lower[n] = upper[n] = X1;
        std::sort(lower, lower + n);
        std::sort(upper, upper + n);
        memset(cnt, 0, sizeof cnt);
        memset(has, 0, sizeof has);
        while (m--)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            ++has[Find(x, y)];
        } /* while */
        puts("Box");
        for (int i = 0; i < n; ++i) ++cnt[has[i]];
        for (int i = 1; i < n; ++i)
            if (cnt[i]) printf("%d: %d\n", i, cnt[i]);
    } /* while */
    return 0;
} /* main */

/*

用二分查找每个玩具所对应的分区即可。

*/
视野动态规划

poj1556 The Doors

/*****************************\
 * @prob: poj1556 The Doors  *
 * @auth: Wang Junji         *
 * @stat: Accepted.          *
 * @date: June. 25th. 2012   *
 * @memo: 视野动态规划        *
\*****************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>

const int maxN = 110;
const double INF = 1e198, zero = 1e-8;

struct vec
{
    double x, y; vec() {} /* vec */
    vec(const double& x, const double& y): x(x), y(y) {} /* vec */
    vec(const vec& b): x(b.x), y(b.y) {} /* vec */
    vec operator-(const vec& b) const
    {return vec(x - b.x, y - b.y);}
    /* operator- */
    double operator*(const vec& b) const
    {return x * b.y - y * b.x;}
    /* operator* */
    vec lwr() const {return vec(x, y - 1);} /* lwr */
    vec upr() const {return vec(x, y + 1);} /* upr */
} p[maxN][4]; int n; double d[maxN][4];

template <typename _Tp>
inline _Tp& gmax(_Tp& a, const _Tp& b)
{return a > b ? a : (a = b);}
/* gmax */

template <typename _Tp>
inline _Tp& gmin(_Tp& a, const _Tp& b)
{return a < b ? a : (a = b);}
/* gmin */

template <typename _Tp> inline _Tp sqr(const _Tp& x) {return x * x;} /* sqr */

inline
bool check(const vec& lwr, const vec& upr,
           const vec& st , const vec& ed)
{
    if (st.x - ed.x > -zero) return false;
    if ((ed  - st) * (lwr - st) > zero) return false;
    if ((upr - st) * (ed  - st) > zero) return false;
    return true;
} /* check */

inline double dist(const vec& a, const vec& b)
{return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));}
/* dist */

inline
void work(const double& val,
          const vec& lwr,
          const vec& upr,
          const vec& st,
          const int& i)
{
    if (val - INF > -zero) return;
    if (d[n][0] - 10 < zero) return;
    if (i == n && check(lwr, upr, st, p[n][0]))
        gmin(d[n][0], val + dist(st, p[n][0]));
    for (int j = 0; j < 4; ++j)
    if (check(lwr, upr, st, p[i][j]))
        gmin(d[i][j], val + dist(st, p[i][j]));
    vec __lwr(lwr), __upr(upr);
    bool ch_lwr = check(lwr, upr, st, p[i][0]),
         ch_upr = check(lwr, upr, st, p[i][1]);
    if (ch_lwr) __lwr = p[i][0];
    if (ch_upr) __upr = p[i][1];
    if (__lwr * __upr > zero && (ch_lwr || ch_upr))
        work(val, __lwr, __upr, st, i + 1);
    __lwr = lwr, __upr = upr;
    ch_lwr = check(lwr, upr, st, p[i][2]);
    ch_upr = check(lwr, upr, st, p[i][3]);
    if (ch_lwr) __lwr = p[i][2];
    if (ch_upr) __upr = p[i][3];
    if (__lwr * __upr > zero && (ch_lwr || ch_upr))
        work(val, __lwr, __upr, st, i + 1);
    return;
} /* work */

int main()
{
    freopen("door.in" , "r", stdin );
    freopen("door.out", "w", stdout);
    while (~scanf("%d", &n) && ~n)
    {
        p[0][0] = vec(0., 5.); ++n;
        for (int i = 1; i < n; ++i)
        {
            double x, y0, y1, y2, y3;
            scanf("%lf%lf%lf%lf%lf", &x, &y0, &y1, &y2, &y3);
            p[i][0] = vec(x, y0);
            p[i][1] = vec(x, y1);
            p[i][2] = vec(x, y2);
            p[i][3] = vec(x, y3);
            d[i][0] = d[i][1] = d[i][2] = d[i][3] = INF;
        } /* for */
        p[n][0] = vec(10., 5.); d[n][0] = INF;
        work(0, p[0][0].lwr(), p[0][0].upr(), p[0][0], 1);
        for (int i = 1; i < n; ++i)
        for (int j = 0; j < 4; ++j)
            work(d[i][j], p[i][j].lwr(), p[i][j].upr(), p[i][j], i + 1);
        printf("%.2lf\n", d[n][0]);
    } /* while */
    return 0;
} /* main */

/*

维护视野的上界和下界,然后依次松弛每个点即可。

*/
凸包、旋转卡壳

UVa681 Convex Hull Finding

/**************************************\
 * @prob: UVa681 Convex Hull Finding  *
 * @auth: Wang Junji                  *
 * @stat: Accepted.                   *
 * @date: June. 26th, 2012            *
 * @memo: 凸包                        *
\**************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

int const maxN = 520;
struct vec
{
    int x, y; vec() {} /* vec */ vec(int x, int y): x(x), y(y) {} /* vec */
    vec operator-(const vec& b) const {return vec(x - b.x,  y - b.y);} /* operator- */
    int operator*(const vec& b) const {return     x * b.y - y * b.x; } /* operator- */
} p[maxN], res[maxN];
int n, T;

inline vec const*
Granham(vec const* const __fir, vec const* const __la, vec* res)
{
    vec* tmp = res + 1; vec const* fir = __fir;
                     if (fir == __la) return res;
    *res++ = *fir++; if (fir == __la) return res;
    *res++ = *fir++; if (fir == __la) return res;
    for (; fir != __la; *res++ = *fir++)
    while (res != tmp && (fir[0] - res[-1]) * (res[-1] - res[-2]) >= 0)
        --res;
    tmp = res; *res++ = __la[-2];
    for (fir = __la - 2; fir-- != __fir; *res++ = *fir)
    while (res != tmp && (fir[0] - res[-1]) * (res[-1] - res[-2]) >= 0)
        --res;
    return res;
} /* Granham */

inline bool cmp(vec const& a, vec const& b)
{return a.y < b.y || (a.y == b.y && a.x < b.x);}
/* cmp */

int main()
{
    freopen("Convex_Hull.in" , "r", stdin );
    freopen("Convex_Hull.out", "w", stdout);
    for (scanf("%d", &T), printf("%d\n", T); T--; ~scanf("\n-1") && puts("-1"))
    {
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
            scanf("%d%d", &p[i].x, &p[i].y);
        std::sort(p, p + n, cmp);
        n = Granham(p, p + n, res) - res;
        printf("%d\n", n);
        for (int i = 0; i < n; ++i)
            printf("%d %d\n", res[i].x, res[i].y);
    } /* for */
    return 0;
} /* main */

/*

凸包的模板题,不再多说。

*/
poj2187 Beauty Contest

/**********************************\
 * @prob: poj2187 Beauty Contest  *
 * @auth: Wang Junji              *
 * @stat: Accepted.               *
 * @date: June. 28th, 2012        *
 * @memo: 旋转卡壳                 *
\**********************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 50010;

struct vec
{
    int x, y; vec() {} /* vec */ vec(int x, int y): x(x), y(y) {} /* vec */
    vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
    int operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
    int sqrabs() const {return x * x + y * y;}
} p[maxN], res[maxN]; int n;

inline int& gmax(int& a, const int& b) {return a > b ? a : (a = b);} /* gmax */

inline bool cmp(const vec& a, const vec& b)
{return a.y < b.y || (a.y == b.y && a.x < b.x);}
/* cmp */

inline const vec*
Granham(const vec* const __fir, const vec* const __la, vec* res)
{
    const vec* fir = __fir;
    const vec* tmp = res + 1;
    for (*res++ = *fir++, *res++ = *fir++; fir != __la; *res++ = *fir++)
    while (res != tmp && (fir[0] - res[-1]) * (res[-1] - res[-2]) >= 0)
        --res;
    tmp = res; *res++ = __la[-2];
    for (fir = __la - 2; fir-- != __fir; *res++ = *fir)
    while (res != tmp && (fir[0] - res[-1]) * (res[-1] - res[-2]) >= 0)
        --res;
    return res - 1;
} /* Granham */

int main()
{
    freopen("Beauty.in" , "r", stdin );
    freopen("Beauty.out", "w", stdout);
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
        scanf("%d%d", &p[i].x, &p[i].y);
    std::sort(p, p + n, cmp);
    n = Granham(p, p + n, res) - res;
    int ans = 0;
    for (const vec *ths = res, *oppo = res + 2; ths != res + n; ++ths)
        //注意这里oppo必须从res + 2开始枚举,否则错。
    {
        while ((oppo[1] - ths[0]) * (oppo[1] - ths[1])
             > (oppo[0] - ths[0]) * (oppo[0] - ths[1]))
            if (++oppo == res + n) oppo = res;
        gmax(ans, (*oppo - *ths).sqrabs());
    } /* for */
    printf("%d\n", ans); return 0;
} /* main */

/*

旋转卡壳模板题,不再多说。

*/
半平面交

poj2451 Uyuw's Concert

/**********************************\
 * @prob: poj2451 Uyuw's Concert  *
 * @auth: Wang Junji              *
 * @stat: Accepted.               *
 * @date: June. 26th. 2012        *
 * @memo: 半平面交                 *
\**********************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <deque>

using std::deque;
typedef double DBL;
const int maxN = 20010;
const DBL zero = 1e-12L;

struct vec
{
    DBL x, y; vec() {} /* vec */ vec(DBL x, DBL y): x(x), y(y) {} /* vec */
    vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
    vec operator+(const vec& b) const {return vec(x + b.x, y + b.y);} /* operator+ */
    vec operator*(const DBL& t) const {return vec(x * t, y * t);} /* operator* */
    DBL operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
} p[maxN];

struct HP
{
    vec A, B; DBL ang; HP() {} /* HP */
    HP(const vec& A, const vec& B): A(A), B(B)
    {ang = atan2(B.y - A.y, B.x - A.x);}
    /* HP */
} hp[maxN]; int n;

inline int sgn(const DBL& x) {return x < -zero ? -1 : x > zero ? 1 : 0;} /* sgn */
inline DBL sqr(const DBL& x) {return x * x;} /* sqr */
inline bool eql(const HP& a, const HP& b) {return !sgn(a.ang - b.ang);} /* eql */
inline bool notin(const vec& P, const HP& a) {return (P - a.B) * (P - a.A) > -zero;} /* notin */

inline int cmp(const void* __a, const void* __b)
{
    const HP &a = *(HP*)__a, &b = *(HP*)__b;
    int tmp = sgn(a.ang - b.ang);
    if (tmp) return tmp;
    return sgn((b.B - a.A) * (b.A - a.A));
} /* cmp */

inline vec cross(const HP& a, const HP& b)
{
    vec AB = a.B - a.A, CD = b.B - b.A,
        AC = b.A - a.A, AD = b.B - a.A;
    return a.A + AB * ((AC * AD) / (AB * CD));
} /* cross */

inline const deque <HP>&
Half_Plane_Inter(const HP* fir, const HP* la)
{
    static deque <HP> q; q.clear();
    for (q.push_back(*fir++), q.push_back(*fir++); fir != la; q.push_back(*fir++))
    {
        while (q.size() > 1 && notin(cross(*(q.end() - 2), q.back()), *fir)) q.pop_back();
        while (q.size() > 1 && notin(cross(q.front(), *(q.begin() + 1)), *fir)) q.pop_front();
    } /* for */
    for (;;)
    {
        bool flag = 0;
        while (q.size() > 2 && notin(cross(*(q.end() - 2), q.back()), q.front()))
            q.pop_back(), flag = 1;
        while (q.size() > 2 && notin(cross(q.front(), *(q.begin() + 1)), q.back()))
            q.pop_front(), flag = 1;
        if (!flag) break;
    } /* for */
    return q;
} /* Half_Plane_Inter */

int main()
{
    freopen("Concert.in" , "r", stdin );
    freopen("Concert.out", "w", stdout);
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
    {
        DBL x1, y1, x2, y2;
        scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
        hp[i] = HP(vec(x1, y1), vec(x2, y2));
    } /* for */
    hp[n++] = HP(vec(0  , 0  ), vec(1e4, 0  ));
    hp[n++] = HP(vec(1e4, 0  ), vec(1e4, 1e4));
    hp[n++] = HP(vec(1e4, 1e4), vec(0  , 1e4));
    hp[n++] = HP(vec(0  , 1e4), vec(0  , 0  ));
    qsort(hp, n, sizeof hp[0], cmp);
    n = std::unique(hp, hp + n, eql) - hp;
    deque <HP> res = Half_Plane_Inter(hp, hp + n);
    if (res.size() < 3) printf("0.0\n");
    else
    {
        n = 0;
        p[n++] = cross(res.front(), res.back());
        for (deque <HP>::const_iterator iter = res.begin(); iter + 1 != res.end(); ++iter)
            p[n++] = cross(*iter, *(iter + 1));
        DBL ans = 0;
        for (int i = 1; i + 1 < n; ++i)
            ans += fabs((p[i + 1] - p[0]) * (p[i] - p[0]));
        printf("%.1lf\n", ans /= 2);
    } /* else */
    return 0;
} /* main */

/*

半平面交的模板题。
注意不能使用long double类型,否则超时。

*/
poj3384 Feng Shui

/*****************************\
 * @prob: poj3384 Feng Shui  *
 * @auth: Wang Junji         *
 * @stat: Accepted.          *
 * @date: June. 28th, 2012   *
 * @memo: 半平面交            *
\*****************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <deque>
#include <cmath>

using std::deque;
const int maxN = 210;
const double zero = 1e-10;

struct vec
{
    double x, y; vec() {} /* vec */ vec(double x, double y): x(x), y(y) {} /* vec */
    vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
    vec operator+(const vec& b) const {return vec(x + b.x, y + b.y);} /* operator+ */
    vec operator*(const double& t) const {return vec(x * t, y * t);} /* operator* */
    double operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
    double abs() const {return sqrt(x * x + y * y);} /* abs */
} p[maxN];

struct HP
{
    vec A, B; double ang; HP() {} /* HP */
    HP(const vec& A, const vec& B): A(A), B(B) {ang = atan2(B.y - A.y, B.x - A.x);} /* HP */
    void mv(const double& r)
    {
        double d = (B - A).abs(), x1 = A.x, x2 = B.x, y1 = A.y, y2 = B.y;
        A.x += (y1 - y2) * r / d;
        B.x += (y1 - y2) * r / d;
        A.y += (x2 - x1) * r / d;
        B.y += (x2 - x1) * r / d;
    } /* mv */
} hp[maxN]; double Rad; int n;

inline int sgn(const double& x) {return x < -zero ? -1 : x > zero ? 1 : 0;} /* sgn */

inline int cmp(const void* __a, const void* __b)
{
    const HP &a = *(HP*)__a, &b = *(HP*)__b;
    int tmp = sgn(a.ang - b.ang);
    if (tmp) return tmp;
    return sgn((b.B - a.A) * (b.A - a.A));
} /* cmp */

inline bool eql(const HP& a, const HP& b) {return !sgn(a.ang - b.ang);} /* eql */

inline vec cross(const HP& a, const HP& b)
{
    vec AB = a.B - a.A, CD = b.B - b.A,
        AC = b.A - a.A, AD = b.B - a.A;
    return a.A + AB * ((AC * AD) / (AB * CD));
} /* cross */

inline bool outof(const vec& P, const HP& a)
{return (P - a.B) * (P - a.A) > zero;}
/* outof */
//这里不能排除三点共线的情况。

inline const deque <HP>&
Half_Plane_Inter(const HP* fir, const HP* la)
{
    static deque <HP> q; q.clear();
    for (q.push_back(*fir++), q.push_back(*fir++); fir != la; q.push_back(*fir++))
    {
        while (q.size() > 1 && outof(cross(*(q.end() - 2), q.back())   , *fir)) q.pop_back ();
        while (q.size() > 1 && outof(cross(q.front(), *(q.begin() + 1)), *fir)) q.pop_front();
    } /* for */
    for (;;)
    {
        bool flag = 0;
        while (q.size() > 2 && outof(cross(*(q.end() - 2), q.back())   , q.front()))
            q.pop_back (), flag = 1;
        while (q.size() > 2 && outof(cross(q.front(), *(q.begin() + 1)), q.back ()))
            q.pop_front(), flag = 1;
        if (!flag) break;
    } /* for */
    return q;
} /* Half_Plane_Inter */

int main()
{
    freopen("Feng_Shui.in" , "r", stdin );
    freopen("Feng_Shui.out", "w", stdout);
    while (~scanf("%d%lf", &n, &Rad))
    {
        for (int i = 0; i < n; ++i)
            scanf("%lf%lf", &p[i].x, &p[i].y);
        p[n] = p[0];
        for (int i = 0; i < n; ++i)
            hp[i] = HP(p[i + 1], p[i]), hp[i].mv(Rad);
        qsort(hp, n, sizeof hp[0], cmp);
        n = std::unique(hp, hp + n, eql) - hp;
        const deque <HP> res = Half_Plane_Inter(hp, hp + n);
        if (res.size() < 3)
        {
            vec tmp = cross(hp[0], hp[1]);
            printf("%.4lf %.4lf %.4lf %.4lf\n", tmp.x, tmp.y, tmp.x, tmp.y);
        } /* if */
        else
        {
            n = 0;
            for (deque <HP>::const_iterator iter = res.begin(); iter + 1 != res.end(); ++iter)
                p[n++] = cross(*iter, *(iter + 1));
            p[n++] = cross(res.back(), res.front());
            p[n] = p[0];
            vec p1, p2;
            double ans = 0;
            for (int i = 0; i + 1 < n; ++i)
            for (int j = i + 1; j < n; ++j)
            {
                double d = (p[i] - p[j]).abs();
                if (d - ans > -zero) ans = d, p1 = p[i], p2 = p[j];
            } /* for */
            if (p1.x > p2.x) std::swap(p1, p2);
            printf("%.4lf %.4lf %.4lf %.4lf\n", p1.x, p1.y, p2.x, p2.y);
        } /* else */
    } /* while */
    return 0;
} /* main */

/*

这道题的Special Judge有点问题,需要注意:
 1) 半平面交时不能排除三点共线的情况(这并不是Sepical Judge的问题,因为这样会排除可能的最优解);
 2) 求最远点对时只能用枚举的方法,不能旋转卡壳;
 3) 输出最后结果时,保证第一个点的横坐标小于第二个点;
 4) 枚举最远点对时,若当前值大于等于最大值时更新,而不是大于。

还要注意半平面交为空的情况,这时候应当通过原始边来找到中间的唯一解。

*/
poj1279 Art Gallery

/*******************************\
 * @prob: poj1279 Art Gallery  *
 * @auth: Wang Junji           *
 * @stat: Accepted.            *
 * @date: June. 28th, 2012     *
 * @memo: 半平面交              *
\*******************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <deque>

using std::deque;
const int maxN = 1510;
const double zero = 1e-8;

struct vec
{
    double x, y; vec() {} /* vec */ vec(double x, double y): x(x), y(y) {} /* vec */
    vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
    vec operator+(const vec& b) const {return vec(x + b.x, y + b.y);} /* operator+ */
    vec operator*(const double& t) const {return vec(x * t, y * t);} /* operator* */
    double operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
} p[maxN];

struct HP
{
    vec A, B; double ang; HP() {} /* HP */
    HP(const vec& A, const vec& B): A(A), B(B)
    {ang = atan2(B.y - A.y, B.x - A.x);} /* HP */
} hp[maxN];
int n, T;

inline int sgn(const double& x)
{return x < -zero ? -1 : x > zero ? 1 : 0;}
/* sgn */

inline bool eql(const HP& a, const HP& b) {return !sgn(a.ang - b.ang);} /* eql */

inline int cmp(const void* __a, const void* __b)
{
    const HP &a = *(HP*)__a, &b = *(HP*)__b;
    int tmp = sgn(a.ang - b.ang);
    if (tmp) return tmp;
    return sgn((b.B - a.A) * (b.A - a.A));
} /* cmp */

inline vec cross(const HP& a, const HP& b)
{
    vec AB = a.B - a.A, CD = b.B - b.A,
        AC = b.A - a.A, AD = b.B - a.A;
    return a.A + AB * ((AC * AD) / (AB * CD));
} /* cross */

inline bool notin(const vec& P, const HP& a)
{return (P - a.B) * (P - a.A) > -zero;}
/* notin */

inline const deque <HP>&
Half_Plane_Inter(const HP* fir, const HP* la)
{
    static deque <HP> q; q.clear();
    for (q.push_back(*fir++), q.push_back(*fir++); fir != la; q.push_back(*fir++))
    {
        while (q.size() > 1 && notin(cross(*(q.end() - 2), q.back())   , *fir)) q.pop_back ();
        while (q.size() > 1 && notin(cross(q.front(), *(q.begin() + 1)), *fir)) q.pop_front();
    } /* for */
    for (;;)
    {
        bool flag = 0;
        while (q.size() > 2 && notin(cross(*(q.end() - 2), q.back())   , q.front()))
            q.pop_back (), flag = 1;
        while (q.size() > 2 && notin(cross(q.front(), *(q.begin() + 1)), q.back ()))
            q.pop_front(), flag = 1;
        if (!flag) break;
    } /* for */
    return q;
} /* Half_Plane_Inter */

int main()
{
    freopen("gallery.in" , "r", stdin );
    freopen("gallery.out", "w", stdout);
    for (scanf("%d", &T); T--;)
    {
        scanf("%d", &n);
        for (int i = 0; i < n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y);
        p[n] = p[0];
        for (int i = 0; i < n; ++i) hp[i] = HP(p[i + 1], p[i]);
        qsort(hp, n, sizeof hp[0], cmp);
        n = std::unique(hp, hp + n, eql) - hp;
        const deque <HP> res = Half_Plane_Inter(hp, hp + n);
        if (res.size() < 3) printf("0.00\n");
        else
        {
            n = 0;
            double ans = 0;
            for (deque <HP>::const_iterator iter = res.begin(); iter + 1 != res.end(); ++iter)
                p[n++] = cross(*iter, *(iter + 1));
            p[n++] = cross(res.front(), res.back());
            for (const vec* ths = p + 1; ths + 1 != p + n; ++ths)
                ans += fabs((ths[0] - p[0]) * (ths[1] - p[0]));
            printf("%.2lf\n", ans /= 2);
        } /* else */
    } /* for */
    return 0;
} /* main */

/*

半平面交模板题,不多说。

*/
poj3525 Most Distant Point from the Sea

/*********************************************************\
 * @prob: poj3525 Most Distant Point from the Sea        *
 * @auth: Wang Junji        * @stat: Accepted.           *
 * @date: June. 26th. 2012  * @memo: 半平面交、二分枚举     *
\*********************************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <deque>
#include <cmath>

using std::deque;
const int maxN = 110;
const double zero = 1e-10;

struct vec
{
    double x, y; vec() {} /* vec */ vec(double x, double y): x(x), y(y) {} /* vec */
    vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
    vec operator+(const vec& b) const {return vec(x + b.x, y + b.y);} /* operator+ */
    vec operator*(const double& t) const {return vec(x * t, y * t);} /* operator* */
    double operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
    double abs() const {return sqrt(x * x + y * y);} /* abs */
} p[maxN];

struct HP
{
    vec A, B; double ang, len; HP() {} /* HP */
    HP(const vec& A, const vec& B): A(A), B(B)
    {
        ang = atan2(B.y - A.y, B.x - A.x);
        len = (B - A).abs();
    } /* HP */
} hp[maxN], hp1[maxN];
int n;

inline int sgn(const double& x)
{return x < -zero ? -1 : x > zero ? 1 : 0;}
/* sgn */

inline double sqr(const double& x) {return x * x;} /* sqr */

inline int cmp(const void* __a, const void* __b)
{
    const HP &a = *(HP*)__a, &b = *(HP*)__b;
    int tmp = sgn(a.ang - b.ang);
    if (tmp) return tmp;
    return sgn((b.B - a.A) * (b.A - a.A));
} /* cmp */

inline bool eql(const HP& a, const HP& b)
{return !sgn(a.ang - b.ang);}
/* eql */

inline vec cross(const HP& a, const HP& b)
{
    vec AB = a.B - a.A, CD = b.B - b.A,
        AC = b.A - a.A, AD = b.B - a.A;
    return a.A + AB * ((AC * AD) / (AB * CD));
} /* cross */

inline bool notin(const vec& P, const HP& a)
{return (P - a.B) * (P - a.A) > -zero;}
/* notin */

inline bool Half_Plane_Inter(const HP* fir, const HP* la)
{
    static deque <HP> q; q.clear();
    for (q.push_back(*fir++), q.push_back(*fir++); fir != la; q.push_back(*fir++))
    {
        while (q.size() > 1 && notin(cross(*(q.end() - 2), q.back())   , *fir)) q.pop_back ();
        while (q.size() > 1 && notin(cross(q.front(), *(q.begin() + 1)), *fir)) q.pop_front();
    } /* for */
    for (;;)
    {
        bool flag = 0;
        while (q.size() > 2 && notin(cross(*(q.end() - 2), q.back())   , q.front()))
            q.pop_back (), flag = 1;
        while (q.size() > 2 && notin(cross(q.front(), *(q.begin() + 1)), q.back ()))
            q.pop_front(), flag = 1;
        if (!flag) break;
    } /* for */
    return q.size() > 2;
} /* Half_Plane_Inter */

inline bool check(double d)
{
    for (int i = 0; i < n; ++i)
    {
        double x1 = hp[i].A.x, x2 = hp[i].B.x,
               y1 = hp[i].A.y, y2 = hp[i].B.y,
               len = hp[i].len;
        hp1[i].A.x = x1 + (y1 - y2) * d / len;
        hp1[i].B.x = x2 + (y1 - y2) * d / len;
        hp1[i].A.y = y1 + (x2 - x1) * d / len;
        hp1[i].B.y = y2 + (x2 - x1) * d / len;
    } /* for */
    return Half_Plane_Inter(hp1, hp1 + n);
} /* check */

int main()
{
    freopen("sea.in" , "r", stdin );
    freopen("sea.out", "w", stdout);
    while (~scanf("%d", &n) && n)
    {
        for (int i = 0; i < n; ++i)
            scanf("%lf%lf", &p[i].x, &p[i].y);
        p[n] = p[0];
        for (int i = 0; i < n; ++i)
            hp[i] = HP(p[i], p[i + 1]);
        std::qsort(hp, n, sizeof hp[0], cmp);
        n = std::unique(hp, hp + n, eql) - hp;
        double L = 0, R = 1e4;
        while (L - R < -zero)
        {
            double Mid = (L + R) / 2;
            if (check(Mid)) L = Mid;
            else R = Mid;
        } /* while */
        printf("%.10lf\n", R);
    } /* while */
    return 0;
} /* main */

/*

相当于是求多边形内切圆半径。
只需要二分枚举,然后将所有的边向内移动半径的距离,求对应的半平面是否有相交的区域。

*/
zoj2820 How I Mathematician Wonder What You Are!

/************************************************************\
 * @prob: zoj2820 How I Mathematician Wonder What You Are!  *
 * @auth: Wang Junji        * @stat: Accepted.              *
 * @date: June. 26th. 2012  * @memo: 半平面交、多边形内核      *
\************************************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <deque>
#include <cmath>

using std::deque;
const int maxN = 50;
const double zero = 1e-8;

struct vec
{
    double x, y; vec() {} /* vec */ vec(const vec& b): x(b.x), y(b.y) {} /* vec */
    vec(double x, double y): x(x), y(y) {} /* vec */
    vec& operator=(const vec& b) {x = b.x, y = b.y; return *this;} /* operator= */
    vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
    vec operator+(const vec& b) const {return vec(x + b.x, y + b.y);} /* operator+ */
    vec operator*(const double& d) const {return vec(x * d, y * d);} /* operator+ */
    double operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
} p[maxN];

struct HP
{
    vec A, B; HP() {} /* HP */ HP(const HP& b): A(b.A), B(b.B) {} /* HP */
    HP(const vec& A, const vec& B): A(A), B(B) {} /* HP */
    HP& operator=(const HP& b) {A = b.A, B = b.B; return *this;} /* HP */
    operator vec() const {return B - A;} /* operator vec */
    double operator*(const HP& b) const {return (B - A) * (b.B - b.A);} /* operator* */
    double angle() const {return atan2(B.y - A.y, B.x - A.x);} /* angle */
} ele[maxN];
int n;

vec cross(const HP& a, const HP& b)
{
    vec AB = vec(a), CD = vec(b),
        AC = b.A - a.A, AD = b.B - a.A;
    return a.A + AB * ((AC * AD) / (AB * CD));
} /* cross */

inline int sgn(const double& x)
{return x < -zero ? -1 : x > zero ? 1 : 0;}
/* sgn */

inline int cmp(const void* __a, const void* __b)
{
    const HP &a = *(HP*)__a, &b = *(HP*)__b;
    int tmp = sgn(a.angle() - b.angle());
    if (tmp) return tmp;
    return sgn((b.B - a.A) * (b.A - a.A));
} /* cmp */

inline bool eql(const HP& a, const HP& b)
{return !sgn(a.angle() - b.angle());}
/* eql */

inline bool notin(const vec& P, const HP& a)
{return (P - a.B) * (P - a.A) > -zero;}
/* notin */

bool Core(HP const* fir, HP const* la)
{
    static deque <HP> q; q.clear();
    for (q.push_back(*fir++), q.push_back(*fir++); fir != la; q.push_back(*fir++))
    {
        while (q.size() > 1 && notin(cross(*(q.end() - 2), q.back()), *fir)) q.pop_back();
        while (q.size() > 1 && notin(cross(q.front(), *(q.begin() + 1)), *fir)) q.pop_front();
    } /* for */
    for (;;)
    {
        bool flag = 0;
        while (q.size() > 2 && notin(cross(*(q.end() - 2), q.back()), q.front()))
            q.pop_back(), flag = 1;
        while (q.size() > 2 && notin(cross(q.front(), *(q.begin() + 1)), q.back()))
            q.pop_front(), flag = 1;
        if (!flag) break;
    } /* for */
    return q.size() > 2;
} /* Core */

int main()
{
    freopen("Core.in" , "r", stdin );
    freopen("Core.out", "w", stdout);
    while (~scanf("%d", &n) && n)
    {
        for (int i = 0; i < n; ++i)
            scanf("%lf%lf", &p[i].x, &p[i].y);
        p[n] = p[0];
        for (int i = 0; i < n; ++i)
            ele[i] = HP(p[i], p[i + 1]);
        qsort(ele, n, sizeof ele[0], cmp);
        n = std::unique(ele, ele + n, eql) - ele;
        printf("%d\n", Core(ele, ele + n));
    } /* while */
    return 0;
} /* main */

/*

半平面交模板题。
参考 http://evalls.yo2.cn/articles/%E5%8D%8A%E5%B9%B3%E9%9D%A2%E4%BA%A4onlogn%E7%9A%84%E7%AE%97%E6%B3%95.html
 1) 将所有半平面按极角排序,对于极角相同的,选择性的保留一个。
 2) 使用一个双端队列(deque),加入最开始2个半平面。
 3) 每次考虑一个新的半平面:
    a. while deque顶端的两个半平面的交点在当前半平面外:删除deque顶端的半平面
    b. while deque底部的两个半平面的交点在当前半平面外:删除deque底部的半平面
    c. 将新半平面加入deque顶端
 4) 删除两端多余的半平面。
    具体方法是:
    a. while deque顶端的两个半平面的交点在底部半平面外:删除deque顶端的半平面
    b. while deque底部的两个半平面的交点在顶端半平面外:删除deque底部的半平面
    重复a, b直到不能删除为止。
 5) 计算出deque顶端和底部的交点即可。

*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值